diff --git a/Makefile b/Makefile index 199115c1..db11b718 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ APPS=init hello sh ls terminal uname compositor drawlines background session kdebug cat yutani-test sysinfo hostname yutani-query env mount date echo nyancat kill ps pstree bim terminal-vga cursor-off font-server migrate free uptime -KERNEL_TARGET=i686-elf +KERNEL_TARGET=i686-pc-toaru KCC = $(KERNEL_TARGET)-gcc KAS = $(KERNEL_TARGET)-as KLD = $(KERNEL_TARGET)-ld +KNM = $(KERNEL_TARGET)-nm CC=i686-pc-toaru-gcc AR=i686-pc-toaru-ar @@ -16,6 +17,54 @@ APPS_X=$(foreach app,$(APPS),base/bin/$(app)) all: image.iso +# Kernel + +KCFLAGS = -O2 -std=c99 +KCFLAGS += -finline-functions -ffreestanding +KCFLAGS += -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format +KCFLAGS += -pedantic -fno-omit-frame-pointer +KCFLAGS += -D_KERNEL_ +KCFLAGS += -DKERNEL_GIT_TAG=$(shell util/make-version) +KASFLAGS = --32 + +KERNEL_OBJS = $(patsubst %.c,%.o,$(wildcard kernel/*.c)) +KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*.c)) +KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*/*.c)) + +KERNEL_ASMOBJS = $(filter-out kernel/symbols.o,$(patsubst %.S,%.o,$(wildcard kernel/*.S))) + +cdrom/kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o + ${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o $@ ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o -lgcc + +kernel/symbols.o: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} util/generate_symbols.py + -rm -f kernel/symbols.o + ${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o .toaruos-kernel ${KERNEL_ASMOBJS} ${KERNEL_OBJS} -lgcc + ${KNM} .toaruos-kernel -g | util/generate_symbols.py > kernel/symbols.S + ${KAS} ${KASFLAGS} kernel/symbols.S -o $@ + -rm -f .toaruos-kernel + +kernel/sys/version.o: kernel/*/*.c kernel/*.c + +cdrom/mod: + @mkdir -p $@ + +MODULES = $(patsubst modules/%.c,cdrom/mod/%.ko,$(wildcard modules/*.c)) + +HEADERS = $(shell find kernel/include/ -type f -name '*.h') + +cdrom/mod/%.ko: modules/%.c ${HEADERS} | cdrom/mod + ${KCC} -T modules/link.ld -I./kernel/include -nostdlib ${KCFLAGS} -c -o $@ $< + +modules: ${MODULES} + +kernel/%.o: kernel/%.S + ${KAS} ${ASFLAGS} $< -o $@ + +kernel/%.o: kernel/%.c ${HEADERS} + ${KCC} ${KCFLAGS} -nostdlib -g -I./kernel/include -c -o $@ $< + +# Root Filesystem + base/dev: mkdir -p base/dev base/tmp: @@ -30,18 +79,24 @@ cdrom/boot: mkdir -p cdrom/boot dirs: base/dev base/tmp base/proc base/bin base/lib cdrom/boot +# C Library + libc/%.o: libc/%.c $(CC) -fPIC -c -m32 -Wa,--32 -O3 -isystem include -o $@ $< -base/lib/ld.so: linker/linker.c base/lib/libnihc.a | dirs - $(CC) -static -Wl,-static $(CFLAGS) -o $@ -Os -T linker/link.ld $< $(LIBS) - base/lib/libnihc.a: ${LIBC_OBJS} | dirs $(AR) cr $@ $^ base/lib/libnihc.so: ${LIBC_OBJS} | dirs $(CC) -o $@ $(CFLAGS) -shared -fPIC $^ +# Userspace Linker/Loader + +base/lib/ld.so: linker/linker.c base/lib/libnihc.a | dirs + $(CC) -static -Wl,-static $(CFLAGS) -o $@ -Os -T linker/link.ld $< $(LIBS) + +# Shared Libraries + base/lib/libtoaru_graphics.so: lib/graphics.c lib/graphics.h $(CC) -o $@ $(CFLAGS) -shared -fPIC $< @@ -81,12 +136,18 @@ base/lib/libtoaru_drawstring.so: lib/drawstring.c lib/drawstring.h base/lib/libt base/lib/libtoaru_decorations.so: lib/decorations.c lib/decorations.h base/lib/libtoaru_graphics.so $(CC) -o $@ $(CFLAGS) -shared -fPIC $< -ltoaru_graphics +# Decoration Themes + base/lib/libtoaru-decor-fancy.so: decors/decor-fancy.c lib/decorations.h base/lib/libtoaru_graphics.so base/lib/libtoaru_decorations.so base/lib/libtoaru_drawstring.so $(CC) -o $@ $(CFLAGS) -shared -fPIC $< -ltoaru_decorations -ltoaru_drawstring -ltoaru_graphics +# Init + base/bin/init: apps/init.c base/lib/libnihc.a | dirs $(CC) -static -Wl,-static $(CFLAGS) -o $@ $< $(LIBS) +# Userspace + base/bin/sh: apps/sh.c base/lib/libnihc.so base/lib/libtoaru_list.so base/lib/libtoaru_rline.so $(CC) $(CFLAGS) -o $@ $< -ltoaru_rline -ltoaru_list -ltoaru_kbd $(LIBS) @@ -132,12 +193,18 @@ base/bin/pstree: apps/pstree.c base/lib/libnihc.so base/lib/libtoaru_tree.so bas base/bin/%: apps/%.c base/lib/libnihc.so | dirs $(CC) $(CFLAGS) -o $@ $< $(LIBS) +# Ramdisk + cdrom/ramdisk.img: ${APPS_X} base/lib/ld.so base/lib/libtoaru-decor-fancy.so Makefile | dirs genext2fs -B 4096 -d base -U -b 4096 -N 2048 cdrom/ramdisk.img -image.iso: cdrom/ramdisk.img cdrom/boot/boot.sys cdrom/kernel +# CD image + +image.iso: cdrom/ramdisk.img cdrom/boot/boot.sys cdrom/kernel ${MODULES} xorriso -as mkisofs -R -J -c boot/bootcat -b boot/boot.sys -no-emul-boot -boot-load-size 20 -o image.iso cdrom +# Boot loader + cdrom/boot/boot.sys: boot/boot.o boot/cstuff.o boot/link.ld | cdrom/boot ${KLD} -T boot/link.ld -o $@ boot/boot.o boot/cstuff.o @@ -157,3 +224,7 @@ clean: rm -f cdrom/ramdisk.img rm -f cdrom/boot/boot.sys rm -f boot/*.o + rm -f cdrom/kernel + rm -f ${KERNEL_OBJS} ${KERNEL_ASMOBJS} + rm -f ${MODULES} + diff --git a/kernel/.gdb_history b/kernel/.gdb_history new file mode 100644 index 00000000..d3d7c7a7 --- /dev/null +++ b/kernel/.gdb_history @@ -0,0 +1,3 @@ +info line *0x00112449 +info line *0x00100ba7 +info line *0x00100ba7 diff --git a/kernel/boot.S b/kernel/boot.S new file mode 100644 index 00000000..6b61b85c --- /dev/null +++ b/kernel/boot.S @@ -0,0 +1,60 @@ +.set MB_MAGIC, 0x1BADB002 +.set MB_FLAG_PAGE_ALIGN, 1 << 0 +.set MB_FLAG_MEMORY_INFO, 1 << 1 +.set MB_FLAG_GRAPHICS, 1 << 2 +.set MB_FLAGS, MB_FLAG_PAGE_ALIGN | MB_FLAG_MEMORY_INFO | MB_FLAG_GRAPHICS +.set MB_CHECKSUM, -(MB_MAGIC + MB_FLAGS) + +.section .multiboot +.align 4 + +/* Multiboot section */ +.long MB_MAGIC +.long MB_FLAGS +.long MB_CHECKSUM +.long 0x00000000 /* header_addr */ +.long 0x00000000 /* load_addr */ +.long 0x00000000 /* load_end_addr */ +.long 0x00000000 /* bss_end_addr */ +.long 0x00000000 /* entry_addr */ + +/* Request linear graphics mode */ +.long 0x00000000 +.long 0 +.long 0 +.long 32 + +/* .stack resides in .bss */ +.section .stack, "aw", @nobits +stack_bottom: +.skip 32768 /* 32KiB */ +stack_top: + +.section .text + +.global start +.type start, @function + +.extern kmain +.type kmain, @function + +start: + /* Setup our stack */ + mov $stack_top, %esp + + /* Make sure our stack is 16-byte aligned */ + and $-16, %esp + + pushl %esp + pushl %eax /* Multiboot header magic */ + pushl %ebx /* Multiboot header pointer */ + + /* Disable interrupts and call kernel proper */ + cli + call kmain + + /* Clear interrupts and hang if we return from kmain */ + cli +hang: + hlt + jmp hang diff --git a/kernel/cpu/gdt.c b/kernel/cpu/gdt.c new file mode 100644 index 00000000..f736f4d8 --- /dev/null +++ b/kernel/cpu/gdt.c @@ -0,0 +1,102 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2013 Kevin Lange + * Copyright (C) 2015 Dale Weiler + * + * Global Descriptor Tables module + * + */ +#include +#include +#include + +typedef struct { + /* Limits */ + uint16_t limit_low; + /* Segment address */ + uint16_t base_low; + uint8_t base_middle; + /* Access modes */ + uint8_t access; + uint8_t granularity; + uint8_t base_high; +} __attribute__((packed)) gdt_entry_t; + +typedef struct { + uint16_t limit; + uintptr_t base; +} __attribute__((packed)) gdt_pointer_t; + +/* In the future we may need to put a lock on the access of this */ +static struct { + gdt_entry_t entries[6]; + gdt_pointer_t pointer; + tss_entry_t tss; +} gdt __attribute__((used)); + +extern void gdt_flush(uintptr_t); + +#define ENTRY(X) (gdt.entries[(X)]) + +void gdt_set_gate(uint8_t num, uint64_t base, uint64_t limit, uint8_t access, uint8_t gran) { + /* Base Address */ + ENTRY(num).base_low = (base & 0xFFFF); + ENTRY(num).base_middle = (base >> 16) & 0xFF; + ENTRY(num).base_high = (base >> 24) & 0xFF; + /* Limits */ + ENTRY(num).limit_low = (limit & 0xFFFF); + ENTRY(num).granularity = (limit >> 16) & 0X0F; + /* Granularity */ + ENTRY(num).granularity |= (gran & 0xF0); + /* Access flags */ + ENTRY(num).access = access; +} + +static void write_tss(int32_t num, uint16_t ss0, uint32_t esp0); + +void gdt_install(void) { + gdt_pointer_t *gdtp = &gdt.pointer; + gdtp->limit = sizeof gdt.entries - 1; + gdtp->base = (uintptr_t)&ENTRY(0); + + gdt_set_gate(0, 0, 0, 0, 0); /* NULL segment */ + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */ + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */ + gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); /* User code */ + gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); /* User data */ + + write_tss(5, 0x10, 0x0); + + /* Go go go */ + gdt_flush((uintptr_t)gdtp); + tss_flush(); +} + +static void write_tss(int32_t num, uint16_t ss0, uint32_t esp0) { + tss_entry_t * tss = &gdt.tss; + uintptr_t base = (uintptr_t)tss; + uintptr_t limit = base + sizeof *tss; + + /* Add the TSS descriptor to the GDT */ + gdt_set_gate(num, base, limit, 0xE9, 0x00); + + memset(tss, 0x0, sizeof *tss); + + tss->ss0 = ss0; + tss->esp0 = esp0; + tss->cs = 0x0b; + tss->ss = 0x13; + tss->ds = 0x13; + tss->es = 0x13; + tss->fs = 0x13; + tss->gs = 0x13; + + tss->iomap_base = sizeof *tss; +} + +void set_kernel_stack(uintptr_t stack) { + /* Set the kernel stack */ + gdt.tss.esp0 = stack; +} + diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c new file mode 100644 index 00000000..10bc4ee0 --- /dev/null +++ b/kernel/cpu/idt.c @@ -0,0 +1,53 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2013 Kevin Lange + * Copyright (C) 2015 Dale Weiler + * + * Interrupt Descriptor Tables + * + */ +#include +#include + +typedef struct { + uint16_t base_low; + uint16_t sel; + uint8_t zero; + uint8_t flags; + uint16_t base_high; +} __attribute__((packed)) idt_entry_t; + +typedef struct { + uint16_t limit; + uintptr_t base; +} __attribute__((packed)) idt_pointer_t; + +/* In the future we may need to put a lock on the access of this */ +static struct { + idt_entry_t entries[256]; + idt_pointer_t pointer; +} idt __attribute__((used)); + +#define ENTRY(X) (idt.entries[(X)]) + +typedef void (*idt_gate_t)(void); + +extern void idt_load(uintptr_t); + +void idt_set_gate(uint8_t num, idt_gate_t base, uint16_t sel, uint8_t flags) { + ENTRY(num).base_low = ((uintptr_t)base & 0xFFFF); + ENTRY(num).base_high = ((uintptr_t)base >> 16) & 0xFFFF; + ENTRY(num).sel = sel; + ENTRY(num).zero = 0; + ENTRY(num).flags = flags | 0x60; +} + +void idt_install(void) { + idt_pointer_t * idtp = &idt.pointer; + idtp->limit = sizeof idt.entries - 1; + idtp->base = (uintptr_t)&ENTRY(0); + memset(&ENTRY(0), 0, sizeof idt.entries); + + idt_load((uintptr_t)idtp); +} diff --git a/kernel/cpu/irq.c b/kernel/cpu/irq.c new file mode 100644 index 00000000..19057580 --- /dev/null +++ b/kernel/cpu/irq.c @@ -0,0 +1,164 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2015 Dale Weiler + * + * Interrupt Requests + * + */ +#include +#include +#include +#include + +/* Programmable interrupt controller */ +#define PIC1 0x20 +#define PIC1_COMMAND PIC1 +#define PIC1_OFFSET 0x20 +#define PIC1_DATA (PIC1+1) + +#define PIC2 0xA0 +#define PIC2_COMMAND PIC2 +#define PIC2_OFFSET 0x28 +#define PIC2_DATA (PIC2+1) + +#define PIC_EOI 0x20 + +#define ICW1_ICW4 0x01 +#define ICW1_INIT 0x10 + +#define PIC_WAIT() \ + do { \ + /* May be fragile */ \ + asm volatile("jmp 1f\n\t" \ + "1:\n\t" \ + " jmp 2f\n\t" \ + "2:"); \ + } while (0) + +/* Interrupts */ +static volatile int sync_depth = 0; + +#define SYNC_CLI() asm volatile("cli") +#define SYNC_STI() asm volatile("sti") + +void int_disable(void) { + /* Check if interrupts are enabled */ + uint32_t flags; + asm volatile("pushf\n\t" + "pop %%eax\n\t" + "movl %%eax, %0\n\t" + : "=r"(flags) + : + : "%eax"); + + /* Disable interrupts */ + SYNC_CLI(); + + /* If interrupts were enabled, then this is the first call depth */ + if (flags & (1 << 9)) { + sync_depth = 1; + } else { + /* Otherwise there is now an additional call depth */ + sync_depth++; + } +} + +void int_resume(void) { + /* If there is one or no call depths, reenable interrupts */ + if (sync_depth == 0 || sync_depth == 1) { + SYNC_STI(); + } else { + sync_depth--; + } +} + +void int_enable(void) { + sync_depth = 0; + SYNC_STI(); +} + +/* Interrupt Requests */ +#define IRQ_CHAIN_SIZE 16 +#define IRQ_CHAIN_DEPTH 4 + +static void (*irqs[IRQ_CHAIN_SIZE])(void); +static irq_handler_chain_t irq_routines[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL }; + +void irq_install_handler(size_t irq, irq_handler_chain_t handler) { + /* Disable interrupts when changing handlers */ + SYNC_CLI(); + for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) { + if (irq_routines[i * IRQ_CHAIN_SIZE + irq]) + continue; + irq_routines[i * IRQ_CHAIN_SIZE + irq] = handler; + break; + } + SYNC_STI(); +} + +void irq_uninstall_handler(size_t irq) { + /* Disable interrupts when changing handlers */ + SYNC_CLI(); + for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) + irq_routines[i * IRQ_CHAIN_SIZE + irq] = NULL; + SYNC_STI(); +} + +static void irq_remap(void) { + /* Cascade initialization */ + outportb(PIC1_COMMAND, ICW1_INIT|ICW1_ICW4); PIC_WAIT(); + outportb(PIC2_COMMAND, ICW1_INIT|ICW1_ICW4); PIC_WAIT(); + + /* Remap */ + outportb(PIC1_DATA, PIC1_OFFSET); PIC_WAIT(); + outportb(PIC2_DATA, PIC2_OFFSET); PIC_WAIT(); + + /* Cascade identity with slave PIC at IRQ2 */ + outportb(PIC1_DATA, 0x04); PIC_WAIT(); + outportb(PIC2_DATA, 0x02); PIC_WAIT(); + + /* Request 8086 mode on each PIC */ + outportb(PIC1_DATA, 0x01); PIC_WAIT(); + outportb(PIC2_DATA, 0x01); PIC_WAIT(); +} + +static void irq_setup_gates(void) { + for (size_t i = 0; i < IRQ_CHAIN_SIZE; i++) { + idt_set_gate(32 + i, irqs[i], 0x08, 0x8E); + } +} + +void irq_install(void) { + char buffer[16]; + for (int i = 0; i < IRQ_CHAIN_SIZE; i++) { + sprintf(buffer, "_irq%d", i); + irqs[i] = symbol_find(buffer); + } + irq_remap(); + irq_setup_gates(); +} + +void irq_ack(size_t irq_no) { + if (irq_no >= 8) { + outportb(PIC2_COMMAND, PIC_EOI); + } + outportb(PIC1_COMMAND, PIC_EOI); +} + +void irq_handler(struct regs *r) { + /* Disable interrupts when handling */ + int_disable(); + if (r->int_no <= 47 && r->int_no >= 32) { + for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) { + irq_handler_chain_t handler = irq_routines[i * IRQ_CHAIN_SIZE + (r->int_no - 32)]; + if (handler && handler(r)) { + goto done; + } + } + irq_ack(r->int_no - 32); + } +done: + int_resume(); +} diff --git a/kernel/cpu/isr.c b/kernel/cpu/isr.c new file mode 100644 index 00000000..c3652277 --- /dev/null +++ b/kernel/cpu/isr.c @@ -0,0 +1,94 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2015 Dale Weiler + * + * Interrupt Service Requests + */ +#include +#include +#include +#include + +/* The count is treated as is when setting up IDT gates. However there is an + * additional ISR for the system call vector which is handled explicitly since + * it's mapped at a different address. + */ +#define ISR_COUNT 32 + +static struct { + size_t index; + void (*stub)(void); +} isrs[32 + 1] __attribute__((used)); + +static irq_handler_t isr_routines[256] = { 0 }; + +void isrs_install_handler(size_t isrs, irq_handler_t handler) { + isr_routines[isrs] = handler; +} + +void isrs_uninstall_handler(size_t isrs) { + isr_routines[isrs] = 0; +} + +void isrs_install(void) { + char buffer[16]; + for (int i = 0; i < ISR_COUNT; i++) { + sprintf(buffer, "_isr%d", i); + isrs[i].index = i; + isrs[i].stub = symbol_find(buffer); + } + isrs[ISR_COUNT].index = SYSCALL_VECTOR; + isrs[ISR_COUNT].stub = symbol_find("_isr127"); + + for (int i = 0; i < ISR_COUNT + 1; i++) { + idt_set_gate(isrs[i].index, isrs[i].stub, 0x08, 0x8E); + } +} + +static const char *exception_messages[32] = { + "Division by zero", + "Debug", + "Non-maskable interrupt", + "Breakpoint", + "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" +}; + +void fault_handler(struct regs * r) { + irq_handler_t handler = isr_routines[r->int_no]; + if (handler) { + handler(r); + } else { + debug_print(CRITICAL, "Unhandled exception: [%d] %s", r->int_no, exception_messages[r->int_no]); + HALT_AND_CATCH_FIRE("Process caused an unhandled exception", r); + STOP; + } +} diff --git a/kernel/devices/cmos.c b/kernel/devices/cmos.c new file mode 100644 index 00000000..6b5e2880 --- /dev/null +++ b/kernel/devices/cmos.c @@ -0,0 +1,194 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * + * CMOS Driver + * + */ + +#include + +/* CMOS values are stored like so: + * Say it's 8:42 AM, then the values are stored as: + * 0x08, 0x42... why this was a good idea, I have no + * clue, but that's how it usually is. + * + * This function will convert between this "BCD" format + * and regular decimal integers. */ +#define from_bcd(val) ((val / 16) * 10 + (val & 0xf)) + +#define CMOS_ADDRESS 0x70 +#define CMOS_DATA 0x71 + +enum +{ + CMOS_SECOND = 0, + CMOS_MINUTE = 2, + CMOS_HOUR = 4, + CMOS_DAY = 7, + CMOS_MONTH = 8, + CMOS_YEAR = 9 +}; + +void +cmos_dump( + uint16_t * values + ) { + uint16_t index; + for (index = 0; index < 128; ++index) { + outportb(CMOS_ADDRESS, index); + values[index] = inportb(CMOS_DATA); + } +} + +int is_update_in_progress(void) +{ + outportb(CMOS_ADDRESS, 0x0a); + return inportb(CMOS_DATA) & 0x80; +} + +/** + * Get the current month and day. + * + * @param month Pointer to a short to store the month + * @param day Pointer to a short to store the day + */ +void +get_date( + uint16_t * month, + uint16_t * day + ) { + uint16_t values[128]; /* CMOS dump */ + cmos_dump(values); + + *month = from_bcd(values[CMOS_MONTH]); + *day = from_bcd(values[CMOS_DAY]); +} + +/** + * Get the current time. + * + * @param hours Pointer to a short to store the current hour (/24) + * @param minutes Pointer to a short to store the current minute + * @param seconds Pointer to a short to store the current second + */ +void +get_time( + uint16_t * hours, + uint16_t * minutes, + uint16_t * seconds + ) { + uint16_t values[128]; /* CMOS dump */ + cmos_dump(values); + + *hours = from_bcd(values[CMOS_HOUR]); + *minutes = from_bcd(values[CMOS_MINUTE]); + *seconds = from_bcd(values[CMOS_SECOND]); +} + +uint32_t secs_of_years(int years) { + uint32_t days = 0; + years += 2000; + while (years > 1969) { + days += 365; + if (years % 4 == 0) { + if (years % 100 == 0) { + if (years % 400 == 0) { + days++; + } + } else { + days++; + } + } + years--; + } + return days * 86400; +} + +uint32_t secs_of_month(int months, int year) { + year += 2000; + + uint32_t days = 0; + switch(months) { + case 11: + days += 30; + case 10: + days += 31; + case 9: + days += 30; + case 8: + days += 31; + case 7: + days += 31; + case 6: + days += 30; + case 5: + days += 31; + case 4: + days += 30; + case 3: + days += 31; + case 2: + days += 28; + if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))) { + days++; + } + case 1: + days += 31; + default: + break; + } + return days * 86400; +} + +uint32_t boot_time = 0; + +uint32_t read_cmos(void) { + uint16_t values[128]; + uint16_t old_values[128]; + + while (is_update_in_progress()) + ; + + cmos_dump(values); + + do + { + memcpy(old_values, values, 128); + while (is_update_in_progress()) + ; + + cmos_dump(values); + } while ((old_values[CMOS_SECOND] != values[CMOS_SECOND]) || + (old_values[CMOS_MINUTE] != values[CMOS_MINUTE]) || + (old_values[CMOS_HOUR] != values[CMOS_HOUR]) || + (old_values[CMOS_DAY] != values[CMOS_DAY]) || + (old_values[CMOS_MONTH] != values[CMOS_MONTH]) || + (old_values[CMOS_YEAR] != values[CMOS_YEAR])); + + /* Math Time */ + uint32_t time = + secs_of_years(from_bcd(values[CMOS_YEAR]) - 1) + + secs_of_month(from_bcd(values[CMOS_MONTH]) - 1, + from_bcd(values[CMOS_YEAR])) + + (from_bcd(values[CMOS_DAY]) - 1) * 86400 + + (from_bcd(values[CMOS_HOUR])) * 3600 + + (from_bcd(values[CMOS_MINUTE])) * 60 + + from_bcd(values[CMOS_SECOND]) + 0; + + return time; +} + +int gettimeofday(struct timeval * t, void *z) { + t->tv_sec = boot_time + timer_ticks + timer_drift; + t->tv_usec = timer_subticks * 1000; + return 0; +} + +uint32_t now(void) { + struct timeval t; + gettimeofday(&t, NULL); + return t.tv_sec; +} + diff --git a/kernel/devices/fpu.c b/kernel/devices/fpu.c new file mode 100644 index 00000000..4407805d --- /dev/null +++ b/kernel/devices/fpu.c @@ -0,0 +1,142 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2013 Kevin Lange + * + * FPU and SSE context handling. + * + * FPU context is kept through context switches, + * but the FPU is disabled. When an FPU instruction + * is executed, it will trap here and the context + * will be saved to its original owner and the context + * for the current process will be loaded or the FPU + * will be reset for the new process. + * + * FPU states are per kernel thread. + * + */ +#include +#include + +#define NO_LAZY_FPU + +process_t * fpu_thread = NULL; + +/** + * Set the FPU control word + * + * @param cw What to set the control word to. + */ +void +set_fpu_cw(const uint16_t cw) { + asm volatile("fldcw %0" :: "m"(cw)); +} + +/** + * Enable the FPU and SSE + */ +void enable_fpu(void) { + asm volatile ("clts"); + size_t t; + asm volatile ("mov %%cr0, %0" : "=r"(t)); + t &= ~(1 << 2); + t |= (1 << 1); + asm volatile ("mov %0, %%cr0" :: "r"(t)); + + asm volatile ("mov %%cr4, %0" : "=r"(t)); + t |= 3 << 9; + asm volatile ("mov %0, %%cr4" :: "r"(t)); + +} + +/** + * Disable FPU and SSE so it traps to the kernel + */ +void disable_fpu(void) { + size_t t; + asm volatile ("mov %%cr0, %0" : "=r"(t)); + t |= 1 << 3; + asm volatile ("mov %0, %%cr0" :: "r"(t)); +} + +/* Temporary aligned buffer for copying around FPU contexts */ +uint8_t saves[512] __attribute__((aligned(16))); + +/** + * Restore the FPU for a process + */ +void restore_fpu(process_t * proc) { + memcpy(&saves,(uint8_t *)&proc->thread.fp_regs,512); + asm volatile ("fxrstor (%0)" :: "r"(saves)); +} + +/** + * Save the FPU for a process + */ +void save_fpu(process_t * proc) { + asm volatile ("fxsave (%0)" :: "r"(saves)); + memcpy((uint8_t *)&proc->thread.fp_regs,&saves,512); +} + +/** + * Initialize the FPU + */ +void init_fpu(void) { + asm volatile ("fninit"); +} + +/** + * Kernel trap for FPU usage when FPU is disabled + */ +void invalid_op(struct regs * r) { + /* First, turn the FPU on */ + enable_fpu(); + if (fpu_thread == current_process) { + /* If this is the thread that last used the FPU, do nothing */ + return; + } + if (fpu_thread) { + /* If there is a thread that was using the FPU, save its state */ + save_fpu(fpu_thread); + } + fpu_thread = (process_t *)current_process; + if (!fpu_thread->thread.fpu_enabled) { + /* + * If the FPU has not been used in this thread previously, + * we need to initialize it. + */ + init_fpu(); + fpu_thread->thread.fpu_enabled = 1; + return; + } + /* Otherwise we restore the context for this thread. */ + restore_fpu(fpu_thread); +} + +/* Called during a context switch; disable the FPU */ +void switch_fpu(void) { +#ifdef NO_LAZY_FPU + save_fpu((process_t *)current_process); +#else + disable_fpu(); +#endif +} + +void unswitch_fpu(void) { +#ifdef NO_LAZY_FPU + restore_fpu((process_t *)current_process); +#endif +} + +/* Enable the FPU context handling */ +void fpu_install(void) { +#ifdef NO_LAZY_FPU + enable_fpu(); + init_fpu(); + save_fpu((void*)current_process); +#else + enable_fpu(); + disable_fpu(); + isrs_install_handler(7, &invalid_op); +#endif +} diff --git a/kernel/devices/pci.c b/kernel/devices/pci.c new file mode 100644 index 00000000..b398b024 --- /dev/null +++ b/kernel/devices/pci.c @@ -0,0 +1,113 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * + * ToAruOS PCI Initialization + */ + +#include +#include +#include + + +void pci_write_field(uint32_t device, int field, int size, uint32_t value) { + outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); + outportl(PCI_VALUE_PORT, value); +} + +uint32_t pci_read_field(uint32_t device, int field, int size) { + outportl(PCI_ADDRESS_PORT, pci_get_addr(device, field)); + + if (size == 4) { + uint32_t t = inportl(PCI_VALUE_PORT); + return t; + } else if (size == 2) { + uint16_t t = inports(PCI_VALUE_PORT + (field & 2)); + return t; + } else if (size == 1) { + uint8_t t = inportb(PCI_VALUE_PORT + (field & 3)); + return t; + } + return 0xFFFF; +} + +uint16_t pci_find_type(uint32_t dev) { + return (pci_read_field(dev, PCI_CLASS, 1) << 8) | pci_read_field(dev, PCI_SUBCLASS, 1); +} + +const char * pci_vendor_lookup(unsigned short vendor_id) { + for (unsigned int i = 0; i < PCI_VENTABLE_LEN; ++i) { + if (PciVenTable[i].VenId == vendor_id) { + return PciVenTable[i].VenFull; + } + } + return ""; +} + +const char * pci_device_lookup(unsigned short vendor_id, unsigned short device_id) { + for (unsigned int i = 0; i < PCI_DEVTABLE_LEN; ++i) { + if (PciDevTable[i].VenId == vendor_id && PciDevTable[i].DevId == device_id) { + return PciDevTable[i].ChipDesc; + } + } + return ""; +} + +void pci_scan_hit(pci_func_t f, uint32_t dev, void * extra) { + int dev_vend = (int)pci_read_field(dev, PCI_VENDOR_ID, 2); + int dev_dvid = (int)pci_read_field(dev, PCI_DEVICE_ID, 2); + + f(dev, dev_vend, dev_dvid, extra); +} + +void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, void * extra) { + uint32_t dev = pci_box_device(bus, slot, func); + if (type == -1 || type == pci_find_type(dev)) { + pci_scan_hit(f, dev, extra); + } + if (pci_find_type(dev) == PCI_TYPE_BRIDGE) { + pci_scan_bus(f, type, pci_read_field(dev, PCI_SECONDARY_BUS, 1), extra); + } +} + +void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void * extra) { + uint32_t dev = pci_box_device(bus, slot, 0); + if (pci_read_field(dev, PCI_VENDOR_ID, 2) == PCI_NONE) { + return; + } + pci_scan_func(f, type, bus, slot, 0, extra); + if (!pci_read_field(dev, PCI_HEADER_TYPE, 1)) { + return; + } + for (int func = 1; func < 8; func++) { + uint32_t dev = pci_box_device(bus, slot, func); + if (pci_read_field(dev, PCI_VENDOR_ID, 2) != PCI_NONE) { + pci_scan_func(f, type, bus, slot, func, extra); + } + } +} + +void pci_scan_bus(pci_func_t f, int type, int bus, void * extra) { + for (int slot = 0; slot < 32; ++slot) { + pci_scan_slot(f, type, bus, slot, extra); + } +} + +void pci_scan(pci_func_t f, int type, void * extra) { + + if ((pci_read_field(0, PCI_HEADER_TYPE, 1) & 0x80) == 0) { + pci_scan_bus(f,type,0,extra); + return; + } + + for (int func = 0; func < 8; ++func) { + uint32_t dev = pci_box_device(0, 0, func); + if (pci_read_field(dev, PCI_VENDOR_ID, 2) != PCI_NONE) { + pci_scan_bus(f, type, func, extra); + } else { + break; + } + } +} + diff --git a/kernel/devices/timer.c b/kernel/devices/timer.c new file mode 100644 index 00000000..a50f5578 --- /dev/null +++ b/kernel/devices/timer.c @@ -0,0 +1,90 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2013 Kevin Lange + * + * Programmable Interrupt Timer + */ +#include +#include +#include + +#define PIT_A 0x40 +#define PIT_B 0x41 +#define PIT_C 0x42 +#define PIT_CONTROL 0x43 + +#define PIT_MASK 0xFF +#define PIT_SCALE 1193180 +#define PIT_SET 0x34 + +#define TIMER_IRQ 0 + +#define SUBTICKS_PER_TICK 1000 +#define RESYNC_TIME 1 + +/* + * Set the phase (in hertz) for the Programmable + * Interrupt Timer (PIT). + */ +void +timer_phase( + int hz + ) { + int divisor = PIT_SCALE / hz; + outportb(PIT_CONTROL, PIT_SET); + outportb(PIT_A, divisor & PIT_MASK); + outportb(PIT_A, (divisor >> 8) & PIT_MASK); +} + +/* + * Internal timer counters + */ +unsigned long timer_ticks = 0; +unsigned long timer_subticks = 0; +signed long timer_drift = 0; +signed long _timer_drift = 0; + +static int behind = 0; + +/* + * IRQ handler for when the timer fires + */ +int timer_handler(struct regs *r) { + if (++timer_subticks == SUBTICKS_PER_TICK || (behind && ++timer_subticks == SUBTICKS_PER_TICK)) { + timer_ticks++; + timer_subticks = 0; + if (timer_ticks % RESYNC_TIME == 0) { + uint32_t new_time = read_cmos(); + _timer_drift = new_time - boot_time - timer_ticks; + if (_timer_drift > 0) behind = 1; + else behind = 0; + } + } + irq_ack(TIMER_IRQ); + + wakeup_sleepers(timer_ticks, timer_subticks); + switch_task(1); + return 1; +} + +void relative_time(unsigned long seconds, unsigned long subseconds, unsigned long * out_seconds, unsigned long * out_subseconds) { + if (subseconds + timer_subticks > SUBTICKS_PER_TICK) { + *out_seconds = timer_ticks + seconds + 1; + *out_subseconds = (subseconds + timer_subticks) - SUBTICKS_PER_TICK; + } else { + *out_seconds = timer_ticks + seconds; + *out_subseconds = timer_subticks + subseconds; + } +} + +/* + * Device installer for the PIT + */ +void timer_install(void) { + debug_print(NOTICE,"Initializing interval timer"); + boot_time = read_cmos(); + irq_install_handler(TIMER_IRQ, timer_handler); + timer_phase(SUBTICKS_PER_TICK); /* 100Hz */ +} + diff --git a/kernel/ds/bitset.c b/kernel/ds/bitset.c new file mode 100644 index 00000000..503ef650 --- /dev/null +++ b/kernel/ds/bitset.c @@ -0,0 +1,64 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015 Dale Weiler + * 2015 Kevin Lange + */ +#include "bitset.h" + +#define CEIL(NUMBER, BASE) \ + (((NUMBER) + (BASE) - 1) & ~((BASE) - 1)) + +#define iom \ + size_t index = bit >> 3; \ + bit = bit - index * 8; \ + size_t offset = bit & 7; \ + size_t mask = 1 << offset; + +void bitset_init(bitset_t *set, size_t size) { + set->size = CEIL(size, 8); + set->data = calloc(set->size, 1); +} + +void bitset_free(bitset_t *set) { + free(set->data); +} + +static void bitset_resize(bitset_t *set, size_t size) { + if (set->size >= size) { + return; + } + + set->data = realloc(set->data, size); + memset(set->data + set->size, 0, size - set->size); + set->size = size; +} + +void bitset_set(bitset_t *set, size_t bit) { + iom; + if (set->size <= index) { + bitset_resize(set, set->size << 1); + } + set->data[index] |= mask; +} + +int bitset_ffub(bitset_t *set) { + for (size_t i = 0; i < set->size * 8; i++) { + if (bitset_test(set, i)) { + continue; + } + return (int)i; + } + return -1; +} + +void bitset_clear(bitset_t *set, size_t bit) { + iom; + set->data[index] &= ~mask; +} + +int bitset_test(bitset_t *set, size_t bit) { + iom; + return !!(mask & set->data[index]); +} + diff --git a/kernel/ds/hashmap.c b/kernel/ds/hashmap.c new file mode 100644 index 00000000..34ed54b1 --- /dev/null +++ b/kernel/ds/hashmap.c @@ -0,0 +1,217 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2014 Kevin Lange + */ +#include "list.h" +#include "hashmap.h" + +unsigned int hashmap_string_hash(void * _key) { + unsigned int hash = 0; + char * key = (char *)_key; + int c; + /* This is the so-called "sdbm" hash. It comes from a piece of + * public domain code from a clone of ndbm. */ + while ((c = *key++)) { + hash = c + (hash << 6) + (hash << 16) - hash; + } + return hash; +} + +int hashmap_string_comp(void * a, void * b) { + return !strcmp(a,b); +} + +void * hashmap_string_dupe(void * key) { + return strdup(key); +} + +unsigned int hashmap_int_hash(void * key) { + return (unsigned int)key; +} + +int hashmap_int_comp(void * a, void * b) { + return (int)a == (int)b; +} + +void * hashmap_int_dupe(void * key) { + return key; +} + +static void hashmap_int_free(void * ptr) { + return; +} + + +hashmap_t * hashmap_create(int size) { + hashmap_t * map = malloc(sizeof(hashmap_t)); + + map->hash_func = &hashmap_string_hash; + map->hash_comp = &hashmap_string_comp; + map->hash_key_dup = &hashmap_string_dupe; + map->hash_key_free = &free; + map->hash_val_free = &free; + + map->size = size; + map->entries = malloc(sizeof(hashmap_entry_t *) * size); + memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size); + + return map; +} + +hashmap_t * hashmap_create_int(int size) { + hashmap_t * map = malloc(sizeof(hashmap_t)); + + map->hash_func = &hashmap_int_hash; + map->hash_comp = &hashmap_int_comp; + map->hash_key_dup = &hashmap_int_dupe; + map->hash_key_free = &hashmap_int_free; + map->hash_val_free = &free; + + map->size = size; + map->entries = malloc(sizeof(hashmap_entry_t *) * size); + memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size); + + return map; +} + +void * hashmap_set(hashmap_t * map, void * key, void * value) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t)); + e->key = map->hash_key_dup(key); + e->value = value; + e->next = NULL; + map->entries[hash] = e; + return NULL; + } else { + hashmap_entry_t * p = NULL; + do { + if (map->hash_comp(x->key, key)) { + void * out = x->value; + x->value = value; + return out; + } else { + p = x; + x = x->next; + } + } while (x); + hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t)); + e->key = map->hash_key_dup(key); + e->value = value; + e->next = NULL; + + p->next = e; + return NULL; + } +} + +void * hashmap_get(hashmap_t * map, void * key) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + return NULL; + } else { + do { + if (map->hash_comp(x->key, key)) { + return x->value; + } + x = x->next; + } while (x); + return NULL; + } +} + +void * hashmap_remove(hashmap_t * map, void * key) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + return NULL; + } else { + if (map->hash_comp(x->key, key)) { + void * out = x->value; + map->entries[hash] = x->next; + map->hash_key_free(x->key); + map->hash_val_free(x); + return out; + } else { + hashmap_entry_t * p = x; + x = x->next; + do { + if (map->hash_comp(x->key, key)) { + void * out = x->value; + p->next = x->next; + map->hash_key_free(x->key); + map->hash_val_free(x); + return out; + } + p = x; + x = x->next; + } while (x); + } + return NULL; + } +} + +int hashmap_has(hashmap_t * map, void * key) { + unsigned int hash = map->hash_func(key) % map->size; + + hashmap_entry_t * x = map->entries[hash]; + if (!x) { + return 0; + } else { + do { + if (map->hash_comp(x->key, key)) { + return 1; + } + x = x->next; + } while (x); + return 0; + } + +} + +list_t * hashmap_keys(hashmap_t * map) { + list_t * l = list_create(); + + for (unsigned int i = 0; i < map->size; ++i) { + hashmap_entry_t * x = map->entries[i]; + while (x) { + list_insert(l, x->key); + x = x->next; + } + } + + return l; +} + +list_t * hashmap_values(hashmap_t * map) { + list_t * l = list_create(); + + for (unsigned int i = 0; i < map->size; ++i) { + hashmap_entry_t * x = map->entries[i]; + while (x) { + list_insert(l, x->value); + x = x->next; + } + } + + return l; +} + +void hashmap_free(hashmap_t * map) { + for (unsigned int i = 0; i < map->size; ++i) { + hashmap_entry_t * x = map->entries[i], * p; + while (x) { + p = x; + x = x->next; + map->hash_key_free(p->key); + map->hash_val_free(p); + } + } + free(map->entries); +} diff --git a/kernel/ds/list.c b/kernel/ds/list.c new file mode 100644 index 00000000..37a0f477 --- /dev/null +++ b/kernel/ds/list.c @@ -0,0 +1,248 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * + * General-purpose list implementations. + */ + +#include "list.h" + +#ifdef _KERNEL_ +# include +#else +# include +# include +#endif + +void list_destroy(list_t * list) { + /* Free all of the contents of a list */ + node_t * n = list->head; + while (n) { + free(n->value); + n = n->next; + } +} + +void list_free(list_t * list) { + /* Free the actual structure of a list */ + node_t * n = list->head; + while (n) { + node_t * s = n->next; + free(n); + n = s; + } +} + +void list_append(list_t * list, node_t * node) { + assert(!(node->next || node->prev) && "Node is already in a list."); + node->next = NULL; + /* Insert a node onto the end of a list */ + node->owner = list; + if (!list->length) { + list->head = node; + list->tail = node; + node->prev = NULL; + node->next = NULL; + list->length++; + return; + } + list->tail->next = node; + node->prev = list->tail; + list->tail = node; + list->length++; +} + +node_t * list_insert(list_t * list, void * item) { + /* Insert an item into a list */ + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + node->owner = NULL; + list_append(list, node); + + return node; +} + +void list_append_after(list_t * list, node_t * before, node_t * node) { + assert(!(node->next || node->prev) && "Node is already in a list."); + node->owner = list; + if (!list->length) { + list_append(list, node); + return; + } + if (before == NULL) { + node->next = list->head; + node->prev = NULL; + list->head->prev = node; + list->head = node; + list->length++; + return; + } + if (before == list->tail) { + list->tail = node; + } else { + before->next->prev = node; + node->next = before->next; + } + node->prev = before; + before->next = node; + list->length++; +} + +node_t * list_insert_after(list_t * list, node_t * before, void * item) { + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + node->owner = NULL; + list_append_after(list, before, node); + return node; +} + +void list_append_before(list_t * list, node_t * after, node_t * node) { + assert(!(node->next || node->prev) && "Node is already in a list."); + node->owner = list; + if (!list->length) { + list_append(list, node); + return; + } + if (after == NULL) { + node->next = NULL; + node->prev = list->tail; + list->tail->next = node; + list->tail = node; + list->length++; + return; + } + if (after == list->head) { + list->head = node; + } else { + after->prev->next = node; + node->prev = after->prev; + } + node->next = after; + after->prev = node; + list->length++; +} + +node_t * list_insert_before(list_t * list, node_t * after, void * item) { + node_t * node = malloc(sizeof(node_t)); + node->value = item; + node->next = NULL; + node->prev = NULL; + node->owner = NULL; + list_append_before(list, after, node); + return node; +} + +list_t * list_create(void) { + /* Create a fresh list */ + list_t * out = malloc(sizeof(list_t)); + out->head = NULL; + out->tail = NULL; + out->length = 0; + return out; +} + +node_t * list_find(list_t * list, void * value) { + foreach(item, list) { + if (item->value == value) { + return item; + } + } + return NULL; +} + +int list_index_of(list_t * list, void * value) { + int i = 0; + foreach(item, list) { + if (item->value == value) { + return i; + } + i++; + } + return -1; /* not find */ +} + +void list_remove(list_t * list, size_t index) { + /* remove index from the list */ + if (index > list->length) return; + size_t i = 0; + node_t * n = list->head; + while (i < index) { + n = n->next; + i++; + } + list_delete(list, n); +} + +void list_delete(list_t * list, node_t * node) { + /* remove node from the list */ + assert(node->owner == list && "Tried to remove a list node from a list it does not belong to."); + if (node == list->head) { + list->head = node->next; + } + if (node == list->tail) { + list->tail = node->prev; + } + if (node->prev) { + node->prev->next = node->next; + } + if (node->next) { + node->next->prev = node->prev; + } + node->prev = NULL; + node->next = NULL; + node->owner = NULL; + list->length--; +} + +node_t * list_pop(list_t * list) { + /* Remove and return the last value in the list + * If you don't need it, you still probably want to free it! + * Try free(list_pop(list)); ! + * */ + if (!list->tail) return NULL; + node_t * out = list->tail; + list_delete(list, out); + return out; +} + +node_t * list_dequeue(list_t * list) { + if (!list->head) return NULL; + node_t * out = list->head; + list_delete(list, out); + return out; +} + +list_t * list_copy(list_t * original) { + /* Create a new copy of original */ + list_t * out = list_create(); + node_t * node = original->head; + while (node) { + list_insert(out, node->value); + } + return out; +} + +void list_merge(list_t * target, list_t * source) { + /* Destructively merges source into target */ + foreach(node, source) { + node->owner = target; + } + if (source->head) { + source->head->prev = target->tail; + } + if (target->tail) { + target->tail->next = source->head; + } else { + target->head = source->head; + } + if (source->tail) { + target->tail = source->tail; + } + target->length += source->length; + free(source); +} diff --git a/kernel/ds/ringbuffer.c b/kernel/ds/ringbuffer.c new file mode 100644 index 00000000..632411d3 --- /dev/null +++ b/kernel/ds/ringbuffer.c @@ -0,0 +1,170 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2014 Kevin Lange + */ +#include +#include +#include + +size_t ring_buffer_unread(ring_buffer_t * ring_buffer) { + if (ring_buffer->read_ptr == ring_buffer->write_ptr) { + return 0; + } + if (ring_buffer->read_ptr > ring_buffer->write_ptr) { + return (ring_buffer->size - ring_buffer->read_ptr) + ring_buffer->write_ptr; + } else { + return (ring_buffer->write_ptr - ring_buffer->read_ptr); + } +} + +size_t ring_buffer_size(fs_node_t * node) { + ring_buffer_t * ring_buffer = (ring_buffer_t *)node->device; + return ring_buffer_unread(ring_buffer); +} + +size_t ring_buffer_available(ring_buffer_t * ring_buffer) { + if (ring_buffer->read_ptr == ring_buffer->write_ptr) { + return ring_buffer->size - 1; + } + + if (ring_buffer->read_ptr > ring_buffer->write_ptr) { + return ring_buffer->read_ptr - ring_buffer->write_ptr - 1; + } else { + return (ring_buffer->size - ring_buffer->write_ptr) + ring_buffer->read_ptr - 1; + } +} + +static inline void ring_buffer_increment_read(ring_buffer_t * ring_buffer) { + ring_buffer->read_ptr++; + if (ring_buffer->read_ptr == ring_buffer->size) { + ring_buffer->read_ptr = 0; + } +} + +static inline void ring_buffer_increment_write(ring_buffer_t * ring_buffer) { + ring_buffer->write_ptr++; + if (ring_buffer->write_ptr == ring_buffer->size) { + ring_buffer->write_ptr = 0; + } +} + +static void ring_buffer_alert_waiters(ring_buffer_t * ring_buffer) { + if (ring_buffer->alert_waiters) { + while (ring_buffer->alert_waiters->head) { + node_t * node = list_dequeue(ring_buffer->alert_waiters); + process_t * p = node->value; + process_alert_node(p, ring_buffer); + free(node); + } + } +} + +void ring_buffer_select_wait(ring_buffer_t * ring_buffer, void * process) { + if (!ring_buffer->alert_waiters) { + ring_buffer->alert_waiters = list_create(); + } + + if (!list_find(ring_buffer->alert_waiters, process)) { + list_insert(ring_buffer->alert_waiters, process); + } + list_insert(((process_t *)process)->node_waits, ring_buffer); +} + +size_t ring_buffer_read(ring_buffer_t * ring_buffer, size_t size, uint8_t * buffer) { + size_t collected = 0; + while (collected == 0) { + spin_lock(ring_buffer->lock); + while (ring_buffer_unread(ring_buffer) > 0 && collected < size) { + buffer[collected] = ring_buffer->buffer[ring_buffer->read_ptr]; + ring_buffer_increment_read(ring_buffer); + collected++; + } + spin_unlock(ring_buffer->lock); + wakeup_queue(ring_buffer->wait_queue_writers); + if (collected == 0) { + if (sleep_on(ring_buffer->wait_queue_readers) && ring_buffer->internal_stop) { + ring_buffer->internal_stop = 0; + break; + } + } + } + wakeup_queue(ring_buffer->wait_queue_writers); + return collected; +} + +size_t ring_buffer_write(ring_buffer_t * ring_buffer, size_t size, uint8_t * buffer) { + size_t written = 0; + while (written < size) { + spin_lock(ring_buffer->lock); + + while (ring_buffer_available(ring_buffer) > 0 && written < size) { + ring_buffer->buffer[ring_buffer->write_ptr] = buffer[written]; + ring_buffer_increment_write(ring_buffer); + written++; + } + + spin_unlock(ring_buffer->lock); + wakeup_queue(ring_buffer->wait_queue_readers); + ring_buffer_alert_waiters(ring_buffer); + if (written < size) { + if (ring_buffer->discard) { + break; + } + if (sleep_on(ring_buffer->wait_queue_writers) && ring_buffer->internal_stop) { + ring_buffer->internal_stop = 0; + break; + } + } + } + + wakeup_queue(ring_buffer->wait_queue_readers); + ring_buffer_alert_waiters(ring_buffer); + return written; +} + +ring_buffer_t * ring_buffer_create(size_t size) { + ring_buffer_t * out = malloc(sizeof(ring_buffer_t)); + + out->buffer = malloc(size); + out->write_ptr = 0; + out->read_ptr = 0; + out->size = size; + out->alert_waiters = NULL; + + spin_init(out->lock); + + out->internal_stop = 0; + out->discard = 0; + + out->wait_queue_readers = list_create(); + out->wait_queue_writers = list_create(); + + return out; +} + +void ring_buffer_destroy(ring_buffer_t * ring_buffer) { + free(ring_buffer->buffer); + + wakeup_queue(ring_buffer->wait_queue_writers); + wakeup_queue(ring_buffer->wait_queue_readers); + ring_buffer_alert_waiters(ring_buffer); + + list_free(ring_buffer->wait_queue_writers); + list_free(ring_buffer->wait_queue_readers); + + free(ring_buffer->wait_queue_writers); + free(ring_buffer->wait_queue_readers); + + if (ring_buffer->alert_waiters) { + list_free(ring_buffer->alert_waiters); + free(ring_buffer->alert_waiters); + } +} + +void ring_buffer_interrupt(ring_buffer_t * ring_buffer) { + ring_buffer->internal_stop = 1; + wakeup_queue_interrupted(ring_buffer->wait_queue_readers); + wakeup_queue_interrupted(ring_buffer->wait_queue_writers); +} + diff --git a/kernel/ds/tree.c b/kernel/ds/tree.c new file mode 100644 index 00000000..92225f8c --- /dev/null +++ b/kernel/ds/tree.c @@ -0,0 +1,192 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * + * General-purpose tree implementation + */ + +#include "tree.h" + +#ifdef _KERNEL_ +# include +#else +# include +# include +#endif + +tree_t * tree_create(void) { + /* Create a new tree */ + tree_t * out = malloc(sizeof(tree_t)); + out->nodes = 0; + out->root = NULL; + return out; +} + +void tree_set_root(tree_t * tree, void * value) { + /* Set the root node for a new tree. */ + tree_node_t * root = tree_node_create(value); + tree->root = root; + tree->nodes = 1; +} + +void tree_node_destroy(tree_node_t * node) { + /* Free the contents of a node and its children, but not the nodes themselves */ + foreach(child, node->children) { + tree_node_destroy((tree_node_t *)child->value); + } + free(node->value); +} + +void tree_destroy(tree_t * tree) { + /* Free the contents of a tree, but not the nodes */ + if (tree->root) { + tree_node_destroy(tree->root); + } +} + +void tree_node_free(tree_node_t * node) { + /* Free a node and its children, but not their contents */ + if (!node) return; + foreach(child, node->children) { + tree_node_free(child->value); + } + free(node); +} + +void tree_free(tree_t * tree) { + /* Free all of the nodes in a tree, but not their contents */ + tree_node_free(tree->root); +} + +tree_node_t * tree_node_create(void * value) { + /* Create a new tree node pointing to the given value */ + tree_node_t * out = malloc(sizeof(tree_node_t)); + out->value = value; + out->children = list_create(); + out->parent = NULL; + return out; +} + +void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node) { + /* Insert a node as a child of parent */ + list_insert(parent->children, node); + node->parent = parent; + tree->nodes++; +} + +tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value) { + /* Insert a (fresh) node as a child of parent */ + tree_node_t * out = tree_node_create(value); + tree_node_insert_child_node(tree, parent, out); + return out; +} + +tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle) { + /* Recursive node part of tree_find_parent */ + tree_node_t * found = NULL; + foreach(child, haystack->children) { + if (child->value == needle) { + return haystack; + } + found = tree_node_find_parent((tree_node_t *)child->value, needle); + if (found) { + break; + } + } + return found; +} + +tree_node_t * tree_find_parent(tree_t * tree, tree_node_t * node) { + /* Return the parent of a node, inefficiently. */ + if (!tree->root) return NULL; + return tree_node_find_parent(tree->root, node); +} + +size_t tree_count_children(tree_node_t * node) { + /* return the number of children this node has */ + if (!node) return 0; + if (!node->children) return 0; + size_t out = node->children->length; + foreach(child, node->children) { + out += tree_count_children((tree_node_t *)child->value); + } + return out; +} + +void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node) { + /* remove a node when we know its parent; update node counts for the tree */ + tree->nodes -= tree_count_children(node) + 1; + list_delete(parent->children, list_find(parent->children, node)); + tree_node_free(node); +} + +void tree_node_remove(tree_t * tree, tree_node_t * node) { + /* remove an entire branch given its root */ + tree_node_t * parent = node->parent; + if (!parent) { + if (node == tree->root) { + tree->nodes = 0; + tree->root = NULL; + tree_node_free(node); + } + } + tree_node_parent_remove(tree, parent, node); +} + +void tree_remove(tree_t * tree, tree_node_t * node) { + /* Remove this node and move its children into its parent's list of children */ + tree_node_t * parent = node->parent; + /* This is something we just can't do. We don't know how to merge our + * children into our "parent" because then we'd have more than one root node. + * A good way to think about this is actually what this tree struct + * primarily exists for: processes. Trying to remove the root is equivalent + * to trying to kill init! Which is bad. We immediately fault on such + * a case anyway ("Tried to kill init, shutting down!"). + */ + if (!parent) return; + tree->nodes--; + list_delete(parent->children, list_find(parent->children, node)); + foreach(child, node->children) { + /* Reassign the parents */ + ((tree_node_t *)child->value)->parent = parent; + } + list_merge(parent->children, node->children); + free(node); +} + +void tree_remove_reparent_root(tree_t * tree, tree_node_t * node) { + /* Remove this node and move its children into the root children */ + tree_node_t * parent = node->parent; + if (!parent) return; + tree->nodes--; + list_delete(parent->children, list_find(parent->children, node)); + foreach(child, node->children) { + /* Reassign the parents */ + ((tree_node_t *)child->value)->parent = tree->root; + } + list_merge(tree->root->children, node->children); + free(node); +} + +void tree_break_off(tree_t * tree, tree_node_t * node) { + tree_node_t * parent = node->parent; + if (!parent) return; + list_delete(parent->children, list_find(parent->children, node)); +} + +tree_node_t * tree_node_find(tree_node_t * node, void * search, tree_comparator_t comparator) { + if (comparator(node->value,search)) { + return node; + } + tree_node_t * found; + foreach(child, node->children) { + found = tree_node_find((tree_node_t *)child->value, search, comparator); + if (found) return found; + } + return NULL; +} + +tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator) { + return tree_node_find(tree->root, value, comparator); +} diff --git a/kernel/fs/pipe.c b/kernel/fs/pipe.c new file mode 100644 index 00000000..1c24f9d9 --- /dev/null +++ b/kernel/fs/pipe.c @@ -0,0 +1,296 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2012-2014 Kevin Lange + * + * Buffered Pipe + * + */ + +#include +#include +#include +#include +#include + +#define DEBUG_PIPES 0 + +uint32_t read_pipe(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +uint32_t write_pipe(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +void open_pipe(fs_node_t *node, unsigned int flags); +void close_pipe(fs_node_t *node); + +static inline size_t pipe_unread(pipe_device_t * pipe) { + if (pipe->read_ptr == pipe->write_ptr) { + return 0; + } + if (pipe->read_ptr > pipe->write_ptr) { + return (pipe->size - pipe->read_ptr) + pipe->write_ptr; + } else { + return (pipe->write_ptr - pipe->read_ptr); + } +} + +int pipe_size(fs_node_t * node) { + pipe_device_t * pipe = (pipe_device_t *)node->device; + return pipe_unread(pipe); +} + +static inline size_t pipe_available(pipe_device_t * pipe) { + if (pipe->read_ptr == pipe->write_ptr) { + return pipe->size - 1; + } + + if (pipe->read_ptr > pipe->write_ptr) { + return pipe->read_ptr - pipe->write_ptr - 1; + } else { + return (pipe->size - pipe->write_ptr) + pipe->read_ptr - 1; + } +} + +int pipe_unsize(fs_node_t * node) { + pipe_device_t * pipe = (pipe_device_t *)node->device; + return pipe_available(pipe); +} + +static inline void pipe_increment_read(pipe_device_t * pipe) { + pipe->read_ptr++; + if (pipe->read_ptr == pipe->size) { + pipe->read_ptr = 0; + } +} + +static inline void pipe_increment_write(pipe_device_t * pipe) { + pipe->write_ptr++; + if (pipe->write_ptr == pipe->size) { + pipe->write_ptr = 0; + } +} + +static inline void pipe_increment_write_by(pipe_device_t * pipe, size_t amount) { + pipe->write_ptr = (pipe->write_ptr + amount) % pipe->size; +} + +static void pipe_alert_waiters(pipe_device_t * pipe) { + if (pipe->alert_waiters) { + while (pipe->alert_waiters->head) { + node_t * node = list_dequeue(pipe->alert_waiters); + process_t * p = node->value; + process_alert_node(p, pipe); + free(node); + } + } +} + +uint32_t read_pipe(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + assert(node->device != 0 && "Attempted to read from a fully-closed pipe."); + + /* Retreive the pipe object associated with this file node */ + pipe_device_t * pipe = (pipe_device_t *)node->device; + +#if DEBUG_PIPES + if (pipe->size > 300) { /* Ignore small pipes (ie, keyboard) */ + debug_print(INFO, "[debug] Call to read from pipe 0x%x", node->device); + debug_print(INFO, " Unread bytes: %d", pipe_unread(pipe)); + debug_print(INFO, " Total size: %d", pipe->size); + debug_print(INFO, " Request size: %d", size); + debug_print(INFO, " Write pointer: %d", pipe->write_ptr); + debug_print(INFO, " Read pointer: %d", pipe->read_ptr); + debug_print(INFO, " Buffer address: 0x%x", pipe->buffer); + } +#endif + + if (pipe->dead) { + debug_print(WARNING, "Pipe is dead?"); + send_signal(getpid(), SIGPIPE); + return 0; + } + + size_t collected = 0; + while (collected == 0) { + spin_lock(pipe->lock_read); + while (pipe_unread(pipe) > 0 && collected < size) { + buffer[collected] = pipe->buffer[pipe->read_ptr]; + pipe_increment_read(pipe); + collected++; + } + spin_unlock(pipe->lock_read); + wakeup_queue(pipe->wait_queue_writers); + /* Deschedule and switch */ + if (collected == 0) { + sleep_on(pipe->wait_queue_readers); + } + } + + return collected; +} + +uint32_t write_pipe(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + assert(node->device != 0 && "Attempted to write to a fully-closed pipe."); + + /* Retreive the pipe object associated with this file node */ + pipe_device_t * pipe = (pipe_device_t *)node->device; + +#if DEBUG_PIPES + if (pipe->size > 300) { /* Ignore small pipes (ie, keyboard) */ + debug_print(INFO, "[debug] Call to write to pipe 0x%x", node->device); + debug_print(INFO, " Available space: %d", pipe_available(pipe)); + debug_print(INFO, " Total size: %d", pipe->size); + debug_print(INFO, " Request size: %d", size); + debug_print(INFO, " Write pointer: %d", pipe->write_ptr); + debug_print(INFO, " Read pointer: %d", pipe->read_ptr); + debug_print(INFO, " Buffer address: 0x%x", pipe->buffer); + debug_print(INFO, " Write: %s", buffer); + } +#endif + + if (pipe->dead) { + debug_print(WARNING, "Pipe is dead?"); + send_signal(getpid(), SIGPIPE); + return 0; + } + + size_t written = 0; + while (written < size) { + spin_lock(pipe->lock_write); + +#if 0 + size_t available = 0; + if (pipe->read_ptr <= pipe->write_ptr) { + available = pipe->size - pipe->write_ptr; + } else { + available = pipe->read_ptr - pipe->write_ptr - 1; + } + if (available) { + available = min(available, size - written); + memcpy(&pipe->buffer[pipe->write_ptr], buffer, available); + pipe_increment_write_by(pipe, available); + written += available; + } +#else + while (pipe_available(pipe) > 0 && written < size) { + pipe->buffer[pipe->write_ptr] = buffer[written]; + pipe_increment_write(pipe); + written++; + } +#endif + + spin_unlock(pipe->lock_write); + wakeup_queue(pipe->wait_queue_readers); + pipe_alert_waiters(pipe); + if (written < size) { + sleep_on(pipe->wait_queue_writers); + } + } + + return written; +} + +void open_pipe(fs_node_t * node, unsigned int flags) { + assert(node->device != 0 && "Attempted to open a fully-closed pipe."); + + /* Retreive the pipe object associated with this file node */ + pipe_device_t * pipe = (pipe_device_t *)node->device; + + /* Add a reference */ + pipe->refcount++; + + return; +} + +void close_pipe(fs_node_t * node) { + assert(node->device != 0 && "Attempted to close an already fully-closed pipe."); + + /* Retreive the pipe object associated with this file node */ + pipe_device_t * pipe = (pipe_device_t *)node->device; + + /* Drop one reference */ + pipe->refcount--; + + /* Check the reference count number */ + if (pipe->refcount == 0) { +#if 0 + /* No other references exist, free the pipe (but not its buffer) */ + free(pipe->buffer); + list_free(pipe->wait_queue); + free(pipe->wait_queue); + free(pipe); + /* And let the creator know there are no more references */ + node->device = 0; +#endif + } + + return; +} + +static int pipe_check(fs_node_t * node) { + pipe_device_t * pipe = (pipe_device_t *)node->device; + + if (pipe_unread(pipe) > 0) { + return 0; + } + + return 1; +} + +static int pipe_wait(fs_node_t * node, void * process) { + pipe_device_t * pipe = (pipe_device_t *)node->device; + + if (!pipe->alert_waiters) { + pipe->alert_waiters = list_create(); + } + + if (!list_find(pipe->alert_waiters, process)) { + list_insert(pipe->alert_waiters, process); + } + list_insert(((process_t *)process)->node_waits, pipe); + + return 0; +} + +fs_node_t * make_pipe(size_t size) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + pipe_device_t * pipe = malloc(sizeof(pipe_device_t)); + memset(fnode, 0, sizeof(fs_node_t)); + memset(pipe, 0, sizeof(pipe_device_t)); + + fnode->device = 0; + fnode->name[0] = '\0'; + sprintf(fnode->name, "[pipe]"); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0666; + fnode->flags = FS_PIPE; + fnode->read = read_pipe; + fnode->write = write_pipe; + fnode->open = open_pipe; + fnode->close = close_pipe; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; /* TODO ioctls for pipes? maybe */ + fnode->get_size = pipe_size; + + fnode->selectcheck = pipe_check; + fnode->selectwait = pipe_wait; + + fnode->atime = now(); + fnode->mtime = fnode->atime; + fnode->ctime = fnode->atime; + + fnode->device = pipe; + + pipe->buffer = malloc(size); + pipe->write_ptr = 0; + pipe->read_ptr = 0; + pipe->size = size; + pipe->refcount = 0; + pipe->dead = 0; + + spin_init(pipe->lock_read); + spin_init(pipe->lock_write); + + pipe->wait_queue_writers = list_create(); + pipe->wait_queue_readers = list_create(); + + return fnode; +} diff --git a/kernel/fs/ramdisk.c b/kernel/fs/ramdisk.c new file mode 100644 index 00000000..6075913e --- /dev/null +++ b/kernel/fs/ramdisk.c @@ -0,0 +1,110 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + * + * Ramdisk driver. + * + * Provide raw block access to files loaded into kernel memory. + */ + +#include +#include +#include +#include +#include +#include + +static uint32_t read_ramdisk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static uint32_t write_ramdisk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static void open_ramdisk(fs_node_t *node, unsigned int flags); +static void close_ramdisk(fs_node_t *node); + +static uint32_t read_ramdisk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + + if (offset > node->length) { + return 0; + } + + if (offset + size > node->length) { + unsigned int i = node->length - offset; + size = i; + } + + memcpy(buffer, (void *)(node->inode + offset), size); + + return size; +} + +static uint32_t write_ramdisk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + if (offset > node->length) { + return 0; + } + + if (offset + size > node->length) { + unsigned int i = node->length - offset; + size = i; + } + + memcpy((void *)(node->inode + offset), buffer, size); + return size; +} + +static void open_ramdisk(fs_node_t * node, unsigned int flags) { + return; +} + +static void close_ramdisk(fs_node_t * node) { + return; +} + +static int ioctl_ramdisk(fs_node_t * node, int request, void * argp) { + switch (request) { + case 0x4001: + if (current_process->user != 0) { + return -EPERM; + } else { + /* Clear all of the memory used by this ramdisk */ + for (uintptr_t i = node->inode; i < node->inode + node->length; i += 0x1000) { + clear_frame(i); + } + /* Mark the file length as 0 */ + node->length = 0; + return 0; + } + default: + return -EINVAL; + } +} + +static fs_node_t * ramdisk_device_create(int device_number, uintptr_t location, size_t size) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = location; + sprintf(fnode->name, "ram%d", device_number); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0660; + fnode->length = size; + fnode->flags = FS_BLOCKDEVICE; + fnode->read = read_ramdisk; + fnode->write = write_ramdisk; + fnode->open = open_ramdisk; + fnode->close = close_ramdisk; + fnode->ioctl = ioctl_ramdisk; + return fnode; +} + +static int last_device_number = 0; +fs_node_t * ramdisk_mount(uintptr_t location, size_t size) { + fs_node_t * ramdisk = ramdisk_device_create(last_device_number, location, size); + if (ramdisk) { + char tmp[64]; + sprintf(tmp, "/dev/%s", ramdisk->name); + vfs_mount(tmp, ramdisk); + last_device_number += 1; + return ramdisk; + } + + return NULL; +} diff --git a/kernel/fs/tty.c b/kernel/fs/tty.c new file mode 100644 index 00000000..3918fe7b --- /dev/null +++ b/kernel/fs/tty.c @@ -0,0 +1,435 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013-2014 Kevin Lange + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TTY_BUFFER_SIZE 4096 +//4096 + +typedef struct pty { + /* the PTY number */ + int name; + + /* Master and slave endpoints */ + fs_node_t * master; + fs_node_t * slave; + + /* term io "window size" struct (width/height) */ + struct winsize size; + + /* termios data structure */ + struct termios tios; + + /* directional pipes */ + ring_buffer_t * in; + ring_buffer_t * out; + + char * canon_buffer; + size_t canon_bufsize; + size_t canon_buflen; + + pid_t ct_proc; /* Controlling process (shell) */ + pid_t fg_proc; /* Foreground process (might also be shell) */ + +} pty_t; + +list_t * pty_list = NULL; + +#define IN(character) ring_buffer_write(pty->in, 1, (uint8_t *)&(character)) +#define OUT(character) ring_buffer_write(pty->out, 1, (uint8_t *)&(character)) + +static void dump_input_buffer(pty_t * pty) { + char * c = pty->canon_buffer; + while (pty->canon_buflen > 0) { + IN(*c); + pty->canon_buflen--; + c++; + } +} + +static void clear_input_buffer(pty_t * pty) { + pty->canon_buflen = 0; + pty->canon_buffer[0] = '\0'; +} + +static void output_process(pty_t * pty, uint8_t c) { + if (ring_buffer_available(pty->out) < 2) return; /* uh oh */ + if (c == '\n' && (pty->tios.c_oflag & ONLCR)) { + uint8_t d = '\r'; + OUT(d); + } + OUT(c); +} + +static void output_process_slave(pty_t * pty, uint8_t c) { + if (c == '\n' && (pty->tios.c_oflag & ONLCR)) { + uint8_t d = '\r'; + OUT(d); + } + OUT(c); +} + +static void input_process(pty_t * pty, uint8_t c) { + if (pty->tios.c_lflag & ICANON) { + if (c == pty->tios.c_cc[VKILL]) { + while (pty->canon_buflen > 0) { + pty->canon_buflen--; + pty->canon_buffer[pty->canon_buflen] = '\0'; + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '\010'); + output_process(pty, ' '); + output_process(pty, '\010'); + } + } + return; + } + if (c == pty->tios.c_cc[VERASE]) { + /* Backspace */ + if (pty->canon_buflen > 0) { + pty->canon_buflen--; + pty->canon_buffer[pty->canon_buflen] = '\0'; + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '\010'); + output_process(pty, ' '); + output_process(pty, '\010'); + } + } + return; + } + if (c == pty->tios.c_cc[VINTR]) { + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '^'); + output_process(pty, '@' + c); + output_process(pty, '\n'); + } + clear_input_buffer(pty); + if (pty->fg_proc) { + send_signal(pty->fg_proc, SIGINT); + } + return; + } + if (c == pty->tios.c_cc[VQUIT]) { + if (pty->tios.c_lflag & ECHO) { + output_process(pty, '^'); + output_process(pty, '@' + c); + output_process(pty, '\n'); + } + clear_input_buffer(pty); + if (pty->fg_proc) { + send_signal(pty->fg_proc, SIGQUIT); + } + return; + } + if (c == pty->tios.c_cc[VEOF]) { + if (pty->canon_buflen) { + dump_input_buffer(pty); + } else { + ring_buffer_interrupt(pty->in); + } + return; + } + if (pty->canon_buflen < pty->canon_bufsize) { + pty->canon_buffer[pty->canon_buflen] = c; + pty->canon_buflen++; + } + if (pty->tios.c_lflag & ECHO) { + output_process(pty, c); + } + if (c == '\n') { + pty->canon_buffer[pty->canon_buflen-1] = c; + dump_input_buffer(pty); + return; + } + return; + } else if (pty->tios.c_lflag & ECHO) { + output_process(pty, c); + } + IN(c); +} + +int pty_ioctl(pty_t * pty, int request, void * argp) { + switch (request) { + case IOCTLDTYPE: + /* + * This is a special toaru-specific call to get a simple + * integer that describes the kind of device this is. + * It's more specific than just "character device" or "file", + * but for here we just need to say we're a TTY. + */ + return IOCTL_DTYPE_TTY; + case TIOCSWINSZ: + if (!argp) return -1; + validate(argp); + memcpy(&pty->size, argp, sizeof(struct winsize)); + /* TODO send sigwinch to fg_prog */ + return 0; + case TIOCGWINSZ: + if (!argp) return -1; + validate(argp); + memcpy(argp, &pty->size, sizeof(struct winsize)); + return 0; + case TCGETS: + if (!argp) return -1; + validate(argp); + memcpy(argp, &pty->tios, sizeof(struct termios)); + return 0; + case TIOCSPGRP: + if (!argp) return -1; + validate(argp); + pty->fg_proc = *(pid_t *)argp; + debug_print(NOTICE, "Setting PTY group to %d", pty->fg_proc); + return 0; + case TIOCGPGRP: + if (!argp) return -1; + validate(argp); + *(pid_t *)argp = pty->fg_proc; + return 0; + case TCSETS: + case TCSETSW: + case TCSETSF: + if (!argp) return -1; + validate(argp); + if (!(((struct termios *)argp)->c_lflag & ICANON) && (pty->tios.c_lflag & ICANON)) { + /* Switch out of canonical mode, the dump the input buffer */ + dump_input_buffer(pty); + } + memcpy(&pty->tios, argp, sizeof(struct termios)); + return 0; + default: + return -EINVAL; + } +} + +uint32_t read_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + pty_t * pty = (pty_t *)node->device; + + /* Standard pipe read */ + return ring_buffer_read(pty->out, size, buffer); +} +uint32_t write_pty_master(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + pty_t * pty = (pty_t *)node->device; + + size_t l = 0; + for (uint8_t * c = buffer; l < size; ++c, ++l) { + input_process(pty, *c); + } + + return l; +} +void open_pty_master(fs_node_t * node, unsigned int flags) { + return; +} +void close_pty_master(fs_node_t * node) { + return; +} + +uint32_t read_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + pty_t * pty = (pty_t *)node->device; + + if (pty->tios.c_lflag & ICANON) { + return ring_buffer_read(pty->in, size, buffer); + } else { + if (pty->tios.c_cc[VMIN] == 0) { + return ring_buffer_read(pty->in, MIN(size, ring_buffer_unread(pty->in)), buffer); + } else { + return ring_buffer_read(pty->in, MIN(pty->tios.c_cc[VMIN], size), buffer); + } + } +} + +uint32_t write_pty_slave(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + pty_t * pty = (pty_t *)node->device; + + size_t l = 0; + for (uint8_t * c = buffer; l < size; ++c, ++l) { + output_process_slave(pty, *c); + } + + return l; +} +void open_pty_slave(fs_node_t * node, unsigned int flags) { + return; +} +void close_pty_slave(fs_node_t * node) { + return; +} + +/* + * These are separate functions just in case I ever feel the need to do + * things differently in the slave or master. + */ +int ioctl_pty_master(fs_node_t * node, int request, void * argp) { + pty_t * pty = (pty_t *)node->device; + return pty_ioctl(pty, request, argp); +} + +int ioctl_pty_slave(fs_node_t * node, int request, void * argp) { + pty_t * pty = (pty_t *)node->device; + return pty_ioctl(pty, request, argp); +} + +int pty_available_input(fs_node_t * node) { + pty_t * pty = (pty_t *)node->device; + return ring_buffer_unread(pty->in); +} + +int pty_available_output(fs_node_t * node) { + pty_t * pty = (pty_t *)node->device; + return ring_buffer_unread(pty->out); +} + +static int check_pty_master(fs_node_t * node) { + pty_t * pty = (pty_t *)node->device; + if (ring_buffer_unread(pty->out) > 0) { + return 0; + } + return 1; +} + +static int check_pty_slave(fs_node_t * node) { + pty_t * pty = (pty_t *)node->device; + if (ring_buffer_unread(pty->in) > 0) { + return 0; + } + return 1; +} + +static int wait_pty_master(fs_node_t * node, void * process) { + pty_t * pty = (pty_t *)node->device; + ring_buffer_select_wait(pty->out, process); + return 0; +} + +static int wait_pty_slave(fs_node_t * node, void * process) { + pty_t * pty = (pty_t *)node->device; + ring_buffer_select_wait(pty->in, process); + return 0; +} + +fs_node_t * pty_master_create(pty_t * pty) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + + fnode->name[0] = '\0'; + sprintf(fnode->name, "pty master"); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0666; + fnode->flags = FS_PIPE; + fnode->read = read_pty_master; + fnode->write = write_pty_master; + fnode->open = open_pty_master; + fnode->close = close_pty_master; + fnode->selectcheck = check_pty_master; + fnode->selectwait = wait_pty_master; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = ioctl_pty_master; + fnode->get_size = pty_available_output; + + fnode->device = pty; + + return fnode; +} + +fs_node_t * pty_slave_create(pty_t * pty) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + + fnode->name[0] = '\0'; + sprintf(fnode->name, "pty slave"); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0666; + fnode->flags = FS_PIPE; + fnode->read = read_pty_slave; + fnode->write = write_pty_slave; + fnode->open = open_pty_slave; + fnode->close = close_pty_slave; + fnode->selectcheck = check_pty_slave; + fnode->selectwait = wait_pty_slave; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = ioctl_pty_slave; + fnode->get_size = pty_available_input; + + fnode->device = pty; + + return fnode; +} + +void pty_install(void) { + pty_list = list_create(); +} + +pty_t * pty_new(struct winsize * size) { + pty_t * pty = malloc(sizeof(pty_t)); + + /* stdin linkage; characters from terminal → PTY slave */ + pty->in = ring_buffer_create(TTY_BUFFER_SIZE); + pty->out = ring_buffer_create(TTY_BUFFER_SIZE); + + pty->in->discard = 1; + + /* Master endpoint - writes go to stdin, reads come from stdout */ + pty->master = pty_master_create(pty); + + /* Slave endpoint, reads come from stdin, writes go to stdout */ + pty->slave = pty_slave_create(pty); + + /* TODO PTY name */ + pty->name = 0; + + if (size) { + memcpy(&pty->size, size, sizeof(struct winsize)); + } else { + /* Sane defaults */ + pty->size.ws_row = 25; + pty->size.ws_col = 80; + } + + /* Controlling and foreground processes are set to 0 by default */ + pty->ct_proc = 0; + pty->fg_proc = 0; + + pty->tios.c_iflag = ICRNL | BRKINT; + pty->tios.c_oflag = ONLCR | OPOST; + pty->tios.c_lflag = ECHO | ECHOE | ECHOK | ICANON | ISIG | IEXTEN; + pty->tios.c_cflag = CREAD; + pty->tios.c_cc[VEOF] = 4; /* ^D */ + pty->tios.c_cc[VEOL] = 0; /* Not set */ + pty->tios.c_cc[VERASE] = '\b'; + pty->tios.c_cc[VINTR] = 3; /* ^C */ + pty->tios.c_cc[VKILL] = 21; /* ^U */ + pty->tios.c_cc[VMIN] = 1; + pty->tios.c_cc[VQUIT] = 28; /* ^\ */ + pty->tios.c_cc[VSTART] = 17; /* ^Q */ + pty->tios.c_cc[VSTOP] = 19; /* ^S */ + pty->tios.c_cc[VSUSP] = 26; /* ^Z */ + pty->tios.c_cc[VTIME] = 0; + + pty->canon_buffer = malloc(TTY_BUFFER_SIZE); + pty->canon_bufsize = TTY_BUFFER_SIZE-2; + pty->canon_buflen = 0; + + return pty; +} + +int pty_create(void *size, fs_node_t ** fs_master, fs_node_t ** fs_slave) { + pty_t * pty = pty_new(size); + + *fs_master = pty->master; + *fs_slave = pty->slave; + + return 0; +} diff --git a/kernel/fs/unixpipe.c b/kernel/fs/unixpipe.c new file mode 100644 index 00000000..93c04567 --- /dev/null +++ b/kernel/fs/unixpipe.c @@ -0,0 +1,150 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include + +#include +#include + +#define UNIX_PIPE_BUFFER 512 + +struct unix_pipe { + fs_node_t * read_end; + fs_node_t * write_end; + + volatile int read_closed; + volatile int write_closed; + + ring_buffer_t * buffer; +}; + +static void close_complete(struct unix_pipe * self) { + ring_buffer_destroy(self->buffer); +} + +static uint32_t read_unixpipe(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + struct unix_pipe * self = node->device; + size_t read = 0; + + while (read < size) { + if (self->write_closed && !ring_buffer_unread(self->buffer)) { + return read; + } + size_t r = ring_buffer_read(self->buffer, 1, buffer+read); + if (r && *((char *)(buffer + read)) == '\n') { + return read+r; + } + read += r; + } + + return read; +} + +static uint32_t write_unixpipe(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + struct unix_pipe * self = node->device; + size_t written = 0; + + while (written < size) { + if (self->read_closed) { + /* SIGPIPE to current process */ + signal_t * sig = malloc(sizeof(signal_t)); + sig->handler = current_process->signals.functions[SIGPIPE]; + sig->signum = SIGPIPE; + handle_signal((process_t *)current_process, sig); + + return written; + } + size_t w = ring_buffer_write(self->buffer, 1, buffer+written); + written += w; + } + + return written; +} + +static void close_read_pipe(fs_node_t * node) { + struct unix_pipe * self = node->device; + + debug_print(NOTICE, "Closing read end of pipe."); + + self->read_closed = 1; + if (self->write_closed) { + debug_print(NOTICE, "Both ends now closed, should clean up."); + } else { + ring_buffer_interrupt(self->buffer); + } +} + +static void close_write_pipe(fs_node_t * node) { + struct unix_pipe * self = node->device; + + debug_print(NOTICE, "Closing write end of pipe."); + + self->write_closed = 1; + if (self->read_closed) { + debug_print(NOTICE, "Both ends now closed, should clean up."); + } else { + ring_buffer_interrupt(self->buffer); + } +} + +static int check_pipe(fs_node_t * node) { + struct unix_pipe * self = node->device; + if (ring_buffer_unread(self->buffer) > 0) { + return 0; + } + return 1; +} + +static int wait_pipe(fs_node_t * node, void * process) { + struct unix_pipe * self = node->device; + ring_buffer_select_wait(self->buffer, process); + return 0; +} + + +int make_unix_pipe(fs_node_t ** pipes) { + size_t size = UNIX_PIPE_BUFFER; + + pipes[0] = malloc(sizeof(fs_node_t)); + pipes[1] = malloc(sizeof(fs_node_t)); + + memset(pipes[0], 0, sizeof(fs_node_t)); + memset(pipes[1], 0, sizeof(fs_node_t)); + + sprintf(pipes[0]->name, "[pipe:read]"); + sprintf(pipes[1]->name, "[pipe:write]"); + + pipes[0]->mask = 0666; + pipes[1]->mask = 0666; + + pipes[0]->flags = FS_PIPE; + pipes[1]->flags = FS_PIPE; + + pipes[0]->read = read_unixpipe; + pipes[1]->write = write_unixpipe; + + pipes[0]->close = close_read_pipe; + pipes[1]->close = close_write_pipe; + + /* Read end can wait */ + pipes[0]->selectcheck = check_pipe; + pipes[0]->selectwait = wait_pipe; + + struct unix_pipe * internals = malloc(sizeof(struct unix_pipe)); + internals->read_end = pipes[0]; + internals->write_end = pipes[1]; + internals->read_closed = 0; + internals->write_closed = 0; + internals->buffer = ring_buffer_create(size); + + pipes[0]->device = internals; + pipes[1]->device = internals; + + return 0; +} diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c new file mode 100644 index 00000000..8ca64039 --- /dev/null +++ b/kernel/fs/vfs.c @@ -0,0 +1,1044 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2014 Lioncash + * Copyright (C) 2012 Tianyi Wang + * + * Virtual File System + * + */ +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SYMLINK_DEPTH 8 +#define MAX_SYMLINK_SIZE 4096 + +tree_t * fs_tree = NULL; /* File system mountpoint tree */ +fs_node_t * fs_root = NULL; /* Pointer to the root mount fs_node (must be some form of filesystem, even ramdisk) */ + +hashmap_t * fs_types = NULL; + + +int has_permission(fs_node_t * node, int permission_bit) { + if (!node) return 0; + + if (current_process->user == 0) { + return 1; + } + + uint32_t permissions = node->mask; + + uint8_t user_perm = (permissions >> 6) & 07; + //uint8_t group_perm = (permissions >> 3) & 07; + uint8_t other_perm = (permissions) & 07; + + if (current_process->user == node->uid) { + return (permission_bit & user_perm); + /* TODO group permissions? */ + } else { + return (permission_bit & other_perm); + } + +} + +static struct dirent * readdir_mapper(fs_node_t *node, uint32_t index) { + tree_node_t * d = (tree_node_t *)node->device; + + if (!d) return NULL; + + if (index == 0) { + struct dirent * dir = malloc(sizeof(struct dirent)); + strcpy(dir->name, "."); + dir->ino = 0; + return dir; + } else if (index == 1) { + struct dirent * dir = malloc(sizeof(struct dirent)); + strcpy(dir->name, ".."); + dir->ino = 1; + return dir; + } + + index -= 2; + unsigned int i = 0; + foreach(child, d->children) { + if (i == index) { + /* Recursively print the children */ + tree_node_t * tchild = (tree_node_t *)child->value; + struct vfs_entry * n = (struct vfs_entry *)tchild->value; + struct dirent * dir = malloc(sizeof(struct dirent)); + + size_t len = strlen(n->name) + 1; + memcpy(&dir->name, n->name, MIN(256, len)); + dir->ino = i; + return dir; + } + ++i; + } + + return NULL; +} + +static fs_node_t * vfs_mapper(void) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->mask = 0666; + fnode->flags = FS_DIRECTORY; + fnode->readdir = readdir_mapper; + return fnode; +} + +/** + * selectcheck_fs: Check if a read from this file would block. + */ +int selectcheck_fs(fs_node_t * node) { + if (!node) return -1; + + if (node->selectcheck) { + return node->selectcheck(node); + } + + return -1; +} + +/** + * selectwait_fs: Inform a node that it should alert the current_process. + */ +int selectwait_fs(fs_node_t * node, void * process) { + if (!node) return -1; + + if (node->selectwait) { + return node->selectwait(node, process); + } + + return -1; +} + +/** + * read_fs: Read a file system node based on its underlying type. + * + * @param node Node to read + * @param offset Offset into the node data to read from + * @param size How much data to read (in bytes) + * @param buffer A buffer to copy of the read data into + * @returns Bytes read + */ +uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + if (!node) return -1; + + if (node->read) { + uint32_t ret = node->read(node, offset, size, buffer); + return ret; + } else { + return -1; + } +} + +/** + * write_fs: Write a file system node based on its underlying type. + * + * @param node Node to write to + * @param offset Offset into the node data to write to + * @param size How much data to write (in bytes) + * @param buffer A buffer to copy from + * @returns Bytes written + */ +uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + if (!node) return -1; + + if (node->write) { + uint32_t ret = node->write(node, offset, size, buffer); + return ret; + } else { + return -1; + } +} + +//volatile uint8_t tmp_refcount_lock = 0; +static spin_lock_t tmp_refcount_lock = { 0 }; + +void vfs_lock(fs_node_t * node) { + spin_lock(tmp_refcount_lock); + node->refcount = -1; + spin_unlock(tmp_refcount_lock); +} + +/** + * open_fs: Open a file system node. + * + * @param node Node to open + * @param flags Same as open, specifies read/write/append/truncate + */ +void open_fs(fs_node_t *node, unsigned int flags) { + + if (!node) return; + + if (node->refcount >= 0) { + spin_lock(tmp_refcount_lock); + node->refcount++; + spin_unlock(tmp_refcount_lock); + } + + if (node->open) { + node->open(node, flags); + } +} + +/** + * close_fs: Close a file system node + * + * @param node Node to close + */ +void close_fs(fs_node_t *node) { + assert(node != fs_root && "Attempted to close the filesystem root. kablooey"); + + if (!node) { + debug_print(WARNING, "Double close? This isn't an fs_node."); + return; + } + + if (node->refcount == -1) return; + + spin_lock(tmp_refcount_lock); + node->refcount--; + if (node->refcount == 0) { + debug_print(NOTICE, "Node refcount [%s] is now 0: %d", node->name, node->refcount); + + if (node->close) { + node->close(node); + } + + free(node); + } + spin_unlock(tmp_refcount_lock); +} + +/** + * chmod_fs + */ +int chmod_fs(fs_node_t *node, int mode) { + if (node->chmod) { + return node->chmod(node, mode); + } + return 0; +} + +/** + * chown_fs + */ +int chown_fs(fs_node_t *node, int uid, int gid) { + if (node->chown) { + return node->chown(node, uid, gid); + } + return 0; +} + +/** + * readdir_fs: Read a directory for the requested index + * + * @param node Directory to read + * @param index Offset to look for + * @returns A dirent object. + */ +struct dirent *readdir_fs(fs_node_t *node, uint32_t index) { + if (!node) return NULL; + + if ((node->flags & FS_DIRECTORY) && node->readdir) { + struct dirent *ret = node->readdir(node, index); + return ret; + } else { + return (struct dirent *)NULL; + } +} + +/** + * finddir_fs: Find the requested file in the directory and return an fs_node for it + * + * @param node Directory to search + * @param name File to look for + * @returns An fs_node that the caller can free + */ +fs_node_t *finddir_fs(fs_node_t *node, char *name) { + if (!node) return NULL; + + if ((node->flags & FS_DIRECTORY) && node->finddir) { + fs_node_t *ret = node->finddir(node, name); + return ret; + } else { + debug_print(WARNING, "Node passed to finddir_fs isn't a directory!"); + debug_print(WARNING, "node = 0x%x, name = %s", node, name); + return (fs_node_t *)NULL; + } +} + +/** + * ioctl_fs: Control Device + * + * @param node Device node to control + * @param request Device-specific request code + * @param argp Depends on `request` + * @returns Depends on `request` + */ +int ioctl_fs(fs_node_t *node, int request, void * argp) { + if (!node) return -1; + + if (node->ioctl) { + return node->ioctl(node, request, argp); + } else { + return -1; /* TODO Should actually be ENOTTY, but we're bad at error numbers */ + } +} + + +/* + * XXX: The following two function should be replaced with + * one function to create children of directory nodes. + * There is no fundamental difference between a directory + * and a file, thus, the use of flag sets should suffice + */ + +int create_file_fs(char *name, uint16_t permission) { + fs_node_t * parent; + char *cwd = (char *)(current_process->wd_name); + char *path = canonicalize_path(cwd, name); + + char * parent_path = malloc(strlen(path) + 4); + sprintf(parent_path, "%s/..", path); + + char * f_path = path + strlen(path) - 1; + while (f_path > path) { + if (*f_path == '/') { + f_path += 1; + break; + } + f_path--; + } + + while (*f_path == '/') { + f_path++; + } + + debug_print(WARNING, "creating file %s within %s (hope these strings are good)", f_path, parent_path); + + parent = kopen(parent_path, 0); + free(parent_path); + + if (!parent) { + debug_print(WARNING, "failed to open parent"); + free(path); + return -1; + } + + if (!has_permission(parent, 02)) { + debug_print(WARNING, "bad permissions"); + return -EACCES; + } + + if (parent->create) { + parent->create(parent, f_path, permission); + } + + free(path); + free(parent); + + return 0; +} + +int unlink_fs(char * name) { + fs_node_t * parent; + char *cwd = (char *)(current_process->wd_name); + char *path = canonicalize_path(cwd, name); + + char * parent_path = malloc(strlen(path) + 4); + sprintf(parent_path, "%s/..", path); + + char * f_path = path + strlen(path) - 1; + while (f_path > path) { + if (*f_path == '/') { + f_path += 1; + break; + } + f_path--; + } + + while (*f_path == '/') { + f_path++; + } + + debug_print(WARNING, "unlinking file %s within %s (hope these strings are good)", f_path, parent_path); + + parent = kopen(parent_path, 0); + free(parent_path); + + if (!parent) { + free(path); + return -1; + } + + if (parent->unlink) { + parent->unlink(parent, f_path); + } + + free(path); + free(parent); + + return 0; +} + +int mkdir_fs(char *name, uint16_t permission) { + fs_node_t * parent; + char *cwd = (char *)(current_process->wd_name); + char *path = canonicalize_path(cwd, name); + + char * parent_path = malloc(strlen(path) + 4); + sprintf(parent_path, "%s/..", path); + + fs_node_t * this = kopen(path, 0); + int _exists = 0; + if (this) { + debug_print(WARNING, "Tried to mkdir a dir that already exists? (%s)", path); + _exists = 1; + } + + char * f_path = path + strlen(path) - 1; + while (f_path > path) { + if (*f_path == '/') { + f_path += 1; + break; + } + f_path--; + } + + while (*f_path == '/') { + f_path++; + } + + debug_print(WARNING, "creating directory %s within %s (hope these strings are good)", f_path, parent_path); + + parent = kopen(parent_path, 0); + free(parent_path); + + if (!parent) { + free(path); + if (_exists) { + return -EEXIST; + } + return -1; + } + + if (parent->mkdir) { + parent->mkdir(parent, f_path, permission); + } + + free(path); + close_fs(parent); + + if (_exists) { + return -EEXIST; + } + return 0; +} + +fs_node_t *clone_fs(fs_node_t *source) { + if (!source) return NULL; + + if (source->refcount >= 0) { + spin_lock(tmp_refcount_lock); + source->refcount++; + spin_unlock(tmp_refcount_lock); + } + + return source; +} + +int symlink_fs(char * target, char * name) { + fs_node_t * parent; + char *cwd = (char *)(current_process->wd_name); + char *path = canonicalize_path(cwd, name); + + char * parent_path = malloc(strlen(path) + 4); + sprintf(parent_path, "%s/..", path); + + char * f_path = path + strlen(path) - 1; + while (f_path > path) { + if (*f_path == '/') { + f_path += 1; + break; + } + f_path--; + } + + debug_print(NOTICE, "creating symlink %s within %s", f_path, parent_path); + + parent = kopen(parent_path, 0); + free(parent_path); + + if (!parent) { + free(path); + return -1; + } + + if (parent->symlink) { + parent->symlink(parent, target, f_path); + } + + free(path); + close_fs(parent); + + return 0; +} + +int readlink_fs(fs_node_t *node, char * buf, uint32_t size) { + if (!node) return -1; + + if (node->readlink) { + return node->readlink(node, buf, size); + } else { + return -1; + } +} + + +/** + * canonicalize_path: Canonicalize a path. + * + * @param cwd Current working directory + * @param input Path to append or canonicalize on + * @returns An absolute path string + */ +char *canonicalize_path(char *cwd, char *input) { + /* This is a stack-based canonicalizer; we use a list as a stack */ + list_t *out = list_create(); + + /* + * If we have a relative path, we need to canonicalize + * the working directory and insert it into the stack. + */ + if (strlen(input) && input[0] != PATH_SEPARATOR) { + /* Make a copy of the working directory */ + char *path = malloc((strlen(cwd) + 1) * sizeof(char)); + memcpy(path, cwd, strlen(cwd) + 1); + + /* Setup tokenizer */ + char *pch; + char *save; + pch = strtok_r(path,PATH_SEPARATOR_STRING,&save); + + /* Start tokenizing */ + while (pch != NULL) { + /* Make copies of the path elements */ + char *s = malloc(sizeof(char) * (strlen(pch) + 1)); + memcpy(s, pch, strlen(pch) + 1); + /* And push them */ + list_insert(out, s); + pch = strtok_r(NULL,PATH_SEPARATOR_STRING,&save); + } + free(path); + } + + /* Similarly, we need to push the elements from the new path */ + char *path = malloc((strlen(input) + 1) * sizeof(char)); + memcpy(path, input, strlen(input) + 1); + + /* Initialize the tokenizer... */ + char *pch; + char *save; + pch = strtok_r(path,PATH_SEPARATOR_STRING,&save); + + /* + * Tokenize the path, this time, taking care to properly + * handle .. and . to represent up (stack pop) and current + * (do nothing) + */ + while (pch != NULL) { + if (!strcmp(pch,PATH_UP)) { + /* + * Path = .. + * Pop the stack to move up a directory + */ + node_t * n = list_pop(out); + if (n) { + free(n->value); + free(n); + } + } else if (!strcmp(pch,PATH_DOT)) { + /* + * Path = . + * Do nothing + */ + } else { + /* + * Regular path, push it + * XXX: Path elements should be checked for existence! + */ + char * s = malloc(sizeof(char) * (strlen(pch) + 1)); + memcpy(s, pch, strlen(pch) + 1); + list_insert(out, s); + } + pch = strtok_r(NULL, PATH_SEPARATOR_STRING, &save); + } + free(path); + + /* Calculate the size of the path string */ + size_t size = 0; + foreach(item, out) { + /* Helpful use of our foreach macro. */ + size += strlen(item->value) + 1; + } + + /* join() the list */ + char *output = malloc(sizeof(char) * (size + 1)); + char *output_offset = output; + if (size == 0) { + /* + * If the path is empty, we take this to mean the root + * thus we synthesize a path of "/" to return. + */ + output = realloc(output, sizeof(char) * 2); + output[0] = PATH_SEPARATOR; + output[1] = '\0'; + } else { + /* Otherwise, append each element together */ + foreach(item, out) { + output_offset[0] = PATH_SEPARATOR; + output_offset++; + memcpy(output_offset, item->value, strlen(item->value) + 1); + output_offset += strlen(item->value); + } + } + + /* Clean up the various things we used to get here */ + list_destroy(out); + list_free(out); + free(out); + + /* And return a working, absolute path */ + return output; +} + +void vfs_install(void) { + /* Initialize the mountpoint tree */ + fs_tree = tree_create(); + + struct vfs_entry * root = malloc(sizeof(struct vfs_entry)); + + root->name = strdup("[root]"); + root->file = NULL; /* Nothing mounted as root */ + root->fs_type = NULL; + root->device = NULL; + + tree_set_root(fs_tree, root); + + fs_types = hashmap_create(5); +} + +int vfs_register(char * name, vfs_mount_callback callback) { + if (hashmap_get(fs_types, name)) return 1; + hashmap_set(fs_types, name, (void *)(uintptr_t)callback); + return 0; +} + +int vfs_mount_type(char * type, char * arg, char * mountpoint) { + + vfs_mount_callback t = (vfs_mount_callback)(uintptr_t)hashmap_get(fs_types, type); + if (!t) { + debug_print(WARNING, "Unknown filesystem type: %s", type); + return -ENODEV; + } + + fs_node_t * n = t(arg, mountpoint); + + if (!n) return -EINVAL; + + tree_node_t * node = vfs_mount(mountpoint, n); + if (node && node->value) { + struct vfs_entry * ent = (struct vfs_entry *)node->value; + ent->fs_type = strdup(type); + ent->device = strdup(arg); + } + + debug_print(NOTICE, "Mounted %s[%s] to %s: 0x%x", type, arg, mountpoint, n); + debug_print_vfs_tree(); + + return 0; +} + +//volatile uint8_t tmp_vfs_lock = 0; +static spin_lock_t tmp_vfs_lock = { 0 }; +/** + * vfs_mount - Mount a file system to the specified path. + * + * For example, if we have an EXT2 filesystem with a root node + * of ext2_root and we want to mount it to /, we would run + * vfs_mount("/", ext2_root); - or, if we have a procfs node, + * we could mount that to /dev/procfs. Individual files can also + * be mounted. + * + * Paths here must be absolute. + */ +void * vfs_mount(char * path, fs_node_t * local_root) { + if (!fs_tree) { + debug_print(ERROR, "VFS hasn't been initialized, you can't mount things yet!"); + return NULL; + } + if (!path || path[0] != '/') { + debug_print(ERROR, "Path must be absolute for mountpoint."); + return NULL; + } + + spin_lock(tmp_vfs_lock); + + local_root->refcount = -1; + + tree_node_t * ret_val = NULL; + + char * p = strdup(path); + char * i = p; + + int path_len = strlen(p); + + /* Chop the path up */ + while (i < p + path_len) { + if (*i == PATH_SEPARATOR) { + *i = '\0'; + } + i++; + } + /* Clean up */ + p[path_len] = '\0'; + i = p + 1; + + /* Root */ + tree_node_t * root_node = fs_tree->root; + + if (*i == '\0') { + /* Special case, we're trying to set the root node */ + struct vfs_entry * root = (struct vfs_entry *)root_node->value; + if (root->file) { + debug_print(WARNING, "Path %s already mounted, unmount before trying to mount something else.", path); + } + root->file = local_root; + /* We also keep a legacy shortcut around for that */ + fs_root = local_root; + ret_val = root_node; + } else { + tree_node_t * node = root_node; + char * at = i; + while (1) { + if (at >= p + path_len) { + break; + } + int found = 0; + debug_print(NOTICE, "Searching for %s", at); + foreach(child, node->children) { + tree_node_t * tchild = (tree_node_t *)child->value; + struct vfs_entry * ent = (struct vfs_entry *)tchild->value; + if (!strcmp(ent->name, at)) { + found = 1; + node = tchild; + ret_val = node; + break; + } + } + if (!found) { + debug_print(NOTICE, "Did not find %s, making it.", at); + struct vfs_entry * ent = malloc(sizeof(struct vfs_entry)); + ent->name = strdup(at); + ent->file = NULL; + ent->device = NULL; + ent->fs_type = NULL; + node = tree_node_insert_child(fs_tree, node, ent); + } + at = at + strlen(at) + 1; + } + struct vfs_entry * ent = (struct vfs_entry *)node->value; + if (ent->file) { + debug_print(WARNING, "Path %s already mounted, unmount before trying to mount something else.", path); + } + ent->file = local_root; + ret_val = node; + } + + free(p); + spin_unlock(tmp_vfs_lock); + return ret_val; +} + +void map_vfs_directory(char * c) { + fs_node_t * f = vfs_mapper(); + struct vfs_entry * e = vfs_mount(c, f); + if (!strcmp(c, "/")) { + f->device = fs_tree->root; + } else { + f->device = e; + } +} + + +void debug_print_vfs_tree_node(tree_node_t * node, size_t height) { + /* End recursion on a blank entry */ + if (!node) return; + char * tmp = malloc(512); + memset(tmp, 0, 512); + char * c = tmp; + /* Indent output */ + for (uint32_t i = 0; i < height; ++i) { + c += sprintf(c, " "); + } + /* Get the current process */ + struct vfs_entry * fnode = (struct vfs_entry *)node->value; + /* Print the process name */ + if (fnode->file) { + c += sprintf(c, "%s → %s 0x%x (%s, %s)", fnode->name, fnode->device, fnode->file, fnode->fs_type, fnode->file->name); + } else { + c += sprintf(c, "%s → (empty)", fnode->name); + } + /* Linefeed */ + debug_print(NOTICE, "%s", tmp); + free(tmp); + foreach(child, node->children) { + /* Recursively print the children */ + debug_print_vfs_tree_node(child->value, height + 1); + } +} + +void debug_print_vfs_tree(void) { + debug_print_vfs_tree_node(fs_tree->root, 0); +} + +/** + * get_mount_point + * + */ +fs_node_t *get_mount_point(char * path, unsigned int path_depth, char **outpath, unsigned int * outdepth) { + size_t depth; + + for (depth = 0; depth <= path_depth; ++depth) { + path += strlen(path) + 1; + } + + /* Last available node */ + fs_node_t * last = fs_root; + tree_node_t * node = fs_tree->root; + + char * at = *outpath; + int _depth = 1; + int _tree_depth = 0; + + while (1) { + if (at >= path) { + break; + } + int found = 0; + debug_print(INFO, "Searching for %s", at); + foreach(child, node->children) { + tree_node_t * tchild = (tree_node_t *)child->value; + struct vfs_entry * ent = (struct vfs_entry *)tchild->value; + if (!strcmp(ent->name, at)) { + found = 1; + node = tchild; + at = at + strlen(at) + 1; + if (ent->file) { + _tree_depth = _depth; + last = ent->file; + *outpath = at; + } + break; + } + } + if (!found) { + break; + } + _depth++; + } + + *outdepth = _tree_depth; + + if (last) { + fs_node_t * last_clone = malloc(sizeof(fs_node_t)); + memcpy(last_clone, last, sizeof(fs_node_t)); + return last_clone; + } + return last; +} + + + +fs_node_t *kopen_recur(char *filename, uint32_t flags, uint32_t symlink_depth, char *relative_to) { + /* Simple sanity checks that we actually have a file system */ + if (!filename) { + return NULL; + } + + /* Canonicalize the (potentially relative) path... */ + char *path = canonicalize_path(relative_to, filename); + /* And store the length once to save recalculations */ + size_t path_len = strlen(path); + + /* If strlen(path) == 1, then path = "/"; return root */ + if (path_len == 1) { + /* Clone the root file system node */ + fs_node_t *root_clone = malloc(sizeof(fs_node_t)); + memcpy(root_clone, fs_root, sizeof(fs_node_t)); + + /* Free the path */ + free(path); + + open_fs(root_clone, flags); + + /* And return the clone */ + return root_clone; + } + + /* Otherwise, we need to break the path up and start searching */ + char *path_offset = path; + uint32_t path_depth = 0; + while (path_offset < path + path_len) { + /* Find each PATH_SEPARATOR */ + if (*path_offset == PATH_SEPARATOR) { + *path_offset = '\0'; + path_depth++; + } + path_offset++; + } + /* Clean up */ + path[path_len] = '\0'; + path_offset = path + 1; + + /* + * At this point, the path is tokenized and path_offset points + * to the first token (directory) and path_depth is the number + * of directories in the path + */ + + /* + * Dig through the (real) tree to find the file + */ + unsigned int depth = 0; + /* Find the mountpoint for this file */ + fs_node_t *node_ptr = get_mount_point(path, path_depth, &path_offset, &depth); + debug_print(INFO, "path_offset: %s", path_offset); + debug_print(INFO, "depth: %d", depth); + + if (!node_ptr) return NULL; + + if (path_offset >= path+path_len) { + free(path); + open_fs(node_ptr, flags); + return node_ptr; + } + fs_node_t *node_next = NULL; + for (; depth < path_depth; ++depth) { + /* Search the active directory for the requested directory */ + debug_print(INFO, "... Searching for %s", path_offset); + node_next = finddir_fs(node_ptr, path_offset); + free(node_ptr); /* Always a clone or an unopened thing */ + node_ptr = node_next; + if (!node_ptr) { + /* We failed to find the requested directory */ + free((void *)path); + return NULL; + } + /* + * This test is a little complicated, but we basically always resolve symlinks in the + * of a path (like /home/symlink/file) even if O_NOFOLLOW and O_PATH are set. If we are + * on the leaf of the path then we will look at those flags and act accordingly + */ + if ((node_ptr->flags & FS_SYMLINK) && + !((flags & O_NOFOLLOW) && (flags & O_PATH) && depth == path_depth - 1)) { + /* This ensures we don't return a path when NOFOLLOW is requested but PATH + * isn't passed. + */ + debug_print(NOTICE, "resolving symlink at %s", node_ptr->name); + if ((flags & O_NOFOLLOW) && depth == path_depth - 1) { + /* TODO(gerow): should probably be setting errno from this */ + debug_print(NOTICE, "Refusing to follow final entry for open with O_NOFOLLOW for %s.", node_ptr->name); + free((void *)path); + free(node_ptr); + return NULL; + } + if (symlink_depth >= MAX_SYMLINK_DEPTH) { + /* TODO(gerow): should probably be setting errno from this */ + debug_print(WARNING, "Reached max symlink depth on %s.", node_ptr->name); + free((void *)path); + free(node_ptr); + return NULL; + } + /* + * This may actually be big enough that we wouldn't want to allocate it on + * the stack, especially considering this function is called recursively + */ + char symlink_buf[MAX_SYMLINK_SIZE]; + int len = readlink_fs(node_ptr, symlink_buf, sizeof(symlink_buf)); + if (len < 0) { + /* TODO(gerow): should probably be setting errno from this */ + debug_print(WARNING, "Got error %d from symlink for %s.", len, node_ptr->name); + free((void *)path); + free(node_ptr); + return NULL; + } + if (symlink_buf[len] != '\0') { + /* TODO(gerow): should probably be setting errno from this */ + debug_print(WARNING, "readlink for %s doesn't end in a null pointer. That's weird...", node_ptr->name); + free((void *)path); + free(node_ptr); + return NULL; + } + fs_node_t * old_node_ptr = node_ptr; + /* Rebuild our path up to this point. This is hella hacky. */ + char * relpath = malloc(path_len + 1); + char * ptr = relpath; + memcpy(relpath, path, path_len + 1); + for (unsigned int i = 0; i < depth; i++) { + while(*ptr != '\0') { + ptr++; + } + *ptr = PATH_SEPARATOR; + } + node_ptr = kopen_recur(symlink_buf, 0, symlink_depth + 1, relpath); + free(relpath); + free(old_node_ptr); + if (!node_ptr) { + /* Dangling symlink? */ + debug_print(WARNING, "Failed to open symlink path %s. Perhaps it's a dangling symlink?", symlink_buf); + free((void *)path); + return NULL; + } + } + if (depth == path_depth - 1) { + /* We found the file and are done, open the node */ + open_fs(node_ptr, flags); + free((void *)path); + return node_ptr; + } + /* We are still searching... */ + path_offset += strlen(path_offset) + 1; + } + debug_print(INFO, "- Not found."); + /* We failed to find the requested file, but our loop terminated. */ + free((void *)path); + return NULL; +} + +/** + * kopen: Open a file by name. + * + * Explore the file system tree to find the appropriate node for + * for a given path. The path can be relative to the working directory + * and will be canonicalized by the kernel. + * + * @param filename Filename to open + * @param flags Flag bits for read/write mode. + * @returns A file system node element that the caller can free. + */ +fs_node_t *kopen(char *filename, uint32_t flags) { + debug_print(NOTICE, "kopen(%s)", filename); + + return kopen_recur(filename, flags, 0, (char *)(current_process->wd_name)); +} + diff --git a/kernel/gdt.S b/kernel/gdt.S new file mode 100644 index 00000000..0be46895 --- /dev/null +++ b/kernel/gdt.S @@ -0,0 +1,20 @@ +.section .text +.align 4 + +.global gdt_flush +.type gdt_flush, @function + +gdt_flush: + /* Load GDT */ + mov 4(%esp), %eax + lgdt (%eax) + + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %ss + + ljmp $0x08, $.flush +.flush: + ret diff --git a/kernel/idt.S b/kernel/idt.S new file mode 100644 index 00000000..d0c31c99 --- /dev/null +++ b/kernel/idt.S @@ -0,0 +1,10 @@ +.section .text +.align 4 + +.global idt_load +.type idt_load, @function + +idt_load: + mov 4(%esp), %eax + lidt (%eax) + ret diff --git a/kernel/include/args.h b/kernel/include/args.h new file mode 100644 index 00000000..0bc5fa08 --- /dev/null +++ b/kernel/include/args.h @@ -0,0 +1,9 @@ +#pragma once + +int args_present(char * karg); +char * args_value(char * karg); +void args_parse(char * _arg); + +void early_stage_args(void); +void late_stage_args(void); + diff --git a/kernel/include/ata.h b/kernel/include/ata.h new file mode 100644 index 00000000..05edb5ce --- /dev/null +++ b/kernel/include/ata.h @@ -0,0 +1,141 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * Values for ATA / PATA devices + */ + +#pragma once + +#define ATA_SR_BSY 0x80 +#define ATA_SR_DRDY 0x40 +#define ATA_SR_DF 0x20 +#define ATA_SR_DSC 0x10 +#define ATA_SR_DRQ 0x08 +#define ATA_SR_CORR 0x04 +#define ATA_SR_IDX 0x02 +#define ATA_SR_ERR 0x01 + +#define ATA_ER_BBK 0x80 +#define ATA_ER_UNC 0x40 +#define ATA_ER_MC 0x20 +#define ATA_ER_IDNF 0x10 +#define ATA_ER_MCR 0x08 +#define ATA_ER_ABRT 0x04 +#define ATA_ER_TK0NF 0x02 +#define ATA_ER_AMNF 0x01 + +#define ATA_CMD_READ_PIO 0x20 +#define ATA_CMD_READ_PIO_EXT 0x24 +#define ATA_CMD_READ_DMA 0xC8 +#define ATA_CMD_READ_DMA_EXT 0x25 +#define ATA_CMD_WRITE_PIO 0x30 +#define ATA_CMD_WRITE_PIO_EXT 0x34 +#define ATA_CMD_WRITE_DMA 0xCA +#define ATA_CMD_WRITE_DMA_EXT 0x35 +#define ATA_CMD_CACHE_FLUSH 0xE7 +#define ATA_CMD_CACHE_FLUSH_EXT 0xEA +#define ATA_CMD_PACKET 0xA0 +#define ATA_CMD_IDENTIFY_PACKET 0xA1 +#define ATA_CMD_IDENTIFY 0xEC + +#define ATAPI_CMD_READ 0xA8 +#define ATAPI_CMD_EJECT 0x1B + +#define ATA_IDENT_DEVICETYPE 0 +#define ATA_IDENT_CYLINDERS 2 +#define ATA_IDENT_HEADS 6 +#define ATA_IDENT_SECTORS 12 +#define ATA_IDENT_SERIAL 20 +#define ATA_IDENT_MODEL 54 +#define ATA_IDENT_CAPABILITIES 98 +#define ATA_IDENT_FIELDVALID 106 +#define ATA_IDENT_MAX_LBA 120 +#define ATA_IDENT_COMMANDSETS 164 +#define ATA_IDENT_MAX_LBA_EXT 200 + +#define IDE_ATA 0x00 +#define IDE_ATAPI 0x01 + +#define ATA_MASTER 0x00 +#define ATA_SLAVE 0x01 + +#define ATA_REG_DATA 0x00 +#define ATA_REG_ERROR 0x01 +#define ATA_REG_FEATURES 0x01 +#define ATA_REG_SECCOUNT0 0x02 +#define ATA_REG_LBA0 0x03 +#define ATA_REG_LBA1 0x04 +#define ATA_REG_LBA2 0x05 +#define ATA_REG_HDDEVSEL 0x06 +#define ATA_REG_COMMAND 0x07 +#define ATA_REG_STATUS 0x07 +#define ATA_REG_SECCOUNT1 0x08 +#define ATA_REG_LBA3 0x09 +#define ATA_REG_LBA4 0x0A +#define ATA_REG_LBA5 0x0B +#define ATA_REG_CONTROL 0x0C +#define ATA_REG_ALTSTATUS 0x0C +#define ATA_REG_DEVADDRESS 0x0D + +// Channels: +#define ATA_PRIMARY 0x00 +#define ATA_SECONDARY 0x01 + +// Directions: +#define ATA_READ 0x00 +#define ATA_WRITE 0x01 + +typedef struct { + uint16_t base; + uint16_t ctrl; + uint16_t bmide; + uint16_t nien; +} ide_channel_regs_t; + +typedef struct { + uint8_t reserved; + uint8_t channel; + uint8_t drive; + uint16_t type; + uint16_t signature; + uint16_t capabilities; + uint32_t command_sets; + uint32_t size; + uint8_t model[41]; +} ide_device_t; + +typedef struct { + uint8_t status; + uint8_t chs_first_sector[3]; + uint8_t type; + uint8_t chs_last_sector[3]; + uint32_t lba_first_sector; + uint32_t sector_count; +} partition_t; + +typedef struct { + uint16_t flags; + uint16_t unused1[9]; + char serial[20]; + uint16_t unused2[3]; + char firmware[8]; + char model[40]; + uint16_t sectors_per_int; + uint16_t unused3; + uint16_t capabilities[2]; + uint16_t unused4[2]; + uint16_t valid_ext_data; + uint16_t unused5[5]; + uint16_t size_of_rw_mult; + uint32_t sectors_28; + uint16_t unused6[38]; + uint64_t sectors_48; + uint16_t unused7[152]; +} __attribute__((packed)) ata_identify_t; + +typedef struct { + uint8_t boostrap[446]; + partition_t partitions[4]; + uint8_t signature[2]; +} __attribute__((packed)) mbr_t; + + diff --git a/kernel/include/bitset.h b/kernel/include/bitset.h new file mode 100644 index 00000000..3e4934d0 --- /dev/null +++ b/kernel/include/bitset.h @@ -0,0 +1,19 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once + +#include + +typedef struct { + unsigned char *data; + size_t size; +} bitset_t; + +void bitset_init(bitset_t *set, size_t size); +void bitset_free(bitset_t *set); +void bitset_set(bitset_t *set, size_t bit); +void bitset_clear(bitset_t *set, size_t bit); +int bitset_test(bitset_t *set, size_t bit); +/* Find first unset bit */ +int bitset_ffub(bitset_t *set); + diff --git a/kernel/include/boot.h b/kernel/include/boot.h new file mode 100644 index 00000000..1a01c826 --- /dev/null +++ b/kernel/include/boot.h @@ -0,0 +1,20 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once +/* + * Boot Information Types + * Used in the kernel boot process to determine + * how we booted and where we can get BIOS + * information from that bootloader. + * + */ +#include + +/* + * Multiboot + * A format managed by GNU and used in GRUB. + * Also supported natively by QEMU and a few + * other emulators. + */ +#include + diff --git a/kernel/include/elf.h b/kernel/include/elf.h new file mode 100644 index 00000000..628e63d7 --- /dev/null +++ b/kernel/include/elf.h @@ -0,0 +1,185 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * ELF Binary Executable headers + * + */ + +#pragma once + +/* + * Different bits of our build environment + * require different header files for definitions + */ +#ifdef _KERNEL_ +# include +#else +# include +#endif + +/* + * Unless otherwise stated, the definitions herein + * are sourced from the Portable Formats Specification, + * version 1.1 - ELF: Executable and Linkable Format + */ + +/* + * ELF Magic Signature + */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define EI_NIDENT 16 + +/* + * ELF Datatypes + */ +typedef uint32_t Elf32_Word; +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint32_t Elf32_Sword; +typedef uint16_t Elf32_Half; + +/* + * ELF Header + */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Header; + +/* + * e_type + */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_LOPROC 0xff0 /* [Processor Specific] */ +#define ET_HIPROC 0xfff /* [Processor Specific] */ + +/* + * Machine types + */ +#define EM_NONE 0 +#define EM_386 3 + +#define EV_NONE 0 +#define EV_CURRENT 1 + +/** Program Header */ +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +/* p_type values */ +#define PT_NULL 0 /* Unused, skip me */ +#define PT_LOAD 1 /* Loadable segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Interpreter (null-terminated string, pathname) */ +#define PT_NOTE 4 /* Auxillary information */ +#define PT_SHLIB 5 /* Reserved. */ +#define PT_PHDR 6 /* Oh, it's me. Hello! Back-reference to the header table itself */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + + +/** Section Header */ +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct { + uint32_t id; + uintptr_t ptr; +} Elf32_auxv; + +typedef struct { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + Elf32_Off d_off; + } d_un; +} Elf32_Dyn; + +/* sh_type values */ +#define SHT_NONE 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_NOBITS 8 +#define SHT_REL 9 + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i) & 0xf) +#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_NUM 3 + +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 +#define STT_NUM 7 + +#define STT_LOPROC 13 +#define STT_HIPROC 15 + diff --git a/kernel/include/errno_defs.h b/kernel/include/errno_defs.h new file mode 120000 index 00000000..3fd3b388 --- /dev/null +++ b/kernel/include/errno_defs.h @@ -0,0 +1 @@ +../../include/errno.h \ No newline at end of file diff --git a/kernel/include/ext2.h b/kernel/include/ext2.h new file mode 100644 index 00000000..5e8cbcb7 --- /dev/null +++ b/kernel/include/ext2.h @@ -0,0 +1,174 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once + +#ifdef _KERNEL_ +# include +#else +# ifdef BOOTLOADER +# include +# else +# include +# endif +#endif + +#define EXT2_SUPER_MAGIC 0xEF53 + +#define EXT2_DIRECT_BLOCKS 12 + +/* Super block struct. */ +struct ext2_superblock { + uint32_t inodes_count; + uint32_t blocks_count; + uint32_t r_blocks_count; + uint32_t free_blocks_count; + uint32_t free_inodes_count; + uint32_t first_data_block; + uint32_t log_block_size; + uint32_t log_frag_size; + uint32_t blocks_per_group; + uint32_t frags_per_group; + uint32_t inodes_per_group; + uint32_t mtime; + uint32_t wtime; + + uint16_t mnt_count; + uint16_t max_mnt_count; + uint16_t magic; + uint16_t state; + uint16_t errors; + uint16_t minor_rev_level; + + uint32_t lastcheck; + uint32_t checkinterval; + uint32_t creator_os; + uint32_t rev_level; + + uint16_t def_resuid; + uint16_t def_resgid; + + /* EXT2_DYNAMIC_REV */ + uint32_t first_ino; + uint16_t inode_size; + uint16_t block_group_nr; + uint32_t feature_compat; + uint32_t feature_incompat; + uint32_t feature_ro_compat; + + uint8_t uuid[16]; + uint8_t volume_name[16]; + + uint8_t last_mounted[64]; + + uint32_t algo_bitmap; + + /* Performance Hints */ + uint8_t prealloc_blocks; + uint8_t prealloc_dir_blocks; + uint16_t _padding; + + /* Journaling Support */ + uint8_t journal_uuid[16]; + uint32_t journal_inum; + uint32_t jounral_dev; + uint32_t last_orphan; + + /* Directory Indexing Support */ + uint32_t hash_seed[4]; + uint8_t def_hash_version; + uint16_t _padding_a; + uint8_t _padding_b; + + /* Other Options */ + uint32_t default_mount_options; + uint32_t first_meta_bg; + uint8_t _unused[760]; + +} __attribute__ ((packed)); + +typedef struct ext2_superblock ext2_superblock_t; + +/* Block group descriptor. */ +struct ext2_bgdescriptor { + uint32_t block_bitmap; + uint32_t inode_bitmap; // block no. of inode bitmap + uint32_t inode_table; + uint16_t free_blocks_count; + uint16_t free_inodes_count; + uint16_t used_dirs_count; + uint16_t pad; + uint8_t reserved[12]; +} __attribute__ ((packed)); + +typedef struct ext2_bgdescriptor ext2_bgdescriptor_t; + +/* File Types */ +#define EXT2_S_IFSOCK 0xC000 +#define EXT2_S_IFLNK 0xA000 +#define EXT2_S_IFREG 0x8000 +#define EXT2_S_IFBLK 0x6000 +#define EXT2_S_IFDIR 0x4000 +#define EXT2_S_IFCHR 0x2000 +#define EXT2_S_IFIFO 0x1000 + +/* setuid, etc. */ +#define EXT2_S_ISUID 0x0800 +#define EXT2_S_ISGID 0x0400 +#define EXT2_S_ISVTX 0x0200 + +/* rights */ +#define EXT2_S_IRUSR 0x0100 +#define EXT2_S_IWUSR 0x0080 +#define EXT2_S_IXUSR 0x0040 +#define EXT2_S_IRGRP 0x0020 +#define EXT2_S_IWGRP 0x0010 +#define EXT2_S_IXGRP 0x0008 +#define EXT2_S_IROTH 0x0004 +#define EXT2_S_IWOTH 0x0002 +#define EXT2_S_IXOTH 0x0001 + +/* This is not actually the inode table. + * It represents an inode in an inode table on disk. */ +struct ext2_inodetable { + uint16_t mode; + uint16_t uid; + uint32_t size; // file length in byte. + uint32_t atime; + uint32_t ctime; + uint32_t mtime; + uint32_t dtime; + uint16_t gid; + uint16_t links_count; + uint32_t blocks; + uint32_t flags; + uint32_t osd1; + uint32_t block[15]; + uint32_t generation; + uint32_t file_acl; + uint32_t dir_acl; + uint32_t faddr; + uint8_t osd2[12]; +} __attribute__ ((packed)); + +typedef struct ext2_inodetable ext2_inodetable_t; + +/* Represents directory entry on disk. */ +struct ext2_dir { + uint32_t inode; + uint16_t rec_len; + uint8_t name_len; + uint8_t file_type; + char name[]; /* Actually a set of characters, at most 255 bytes */ +} __attribute__ ((packed)); + +typedef struct ext2_dir ext2_dir_t; + +typedef struct { + uint32_t block_no; + uint32_t last_use; + uint8_t dirty; + uint8_t *block; +} ext2_disk_cache_entry_t; + +typedef int (*ext2_block_io_t) (void *, uint32_t, uint8_t *); + diff --git a/kernel/include/fs.h b/kernel/include/fs.h new file mode 100644 index 00000000..d207f0d4 --- /dev/null +++ b/kernel/include/fs.h @@ -0,0 +1,170 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ + +#pragma once + +#define PATH_SEPARATOR '/' +#define PATH_SEPARATOR_STRING "/" +#define PATH_UP ".." +#define PATH_DOT "." + +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_APPEND 0x0008 +#define O_CREAT 0x0200 +#define O_TRUNC 0x0400 +#define O_EXCL 0x0800 +#define O_NOFOLLOW 0x1000 +#define O_PATH 0x2000 + +#define FS_FILE 0x01 +#define FS_DIRECTORY 0x02 +#define FS_CHARDEVICE 0x04 +#define FS_BLOCKDEVICE 0x08 +#define FS_PIPE 0x10 +#define FS_SYMLINK 0x20 +#define FS_MOUNTPOINT 0x40 + +#define _IFMT 0170000 /* type of file */ +#define _IFDIR 0040000 /* directory */ +#define _IFCHR 0020000 /* character special */ +#define _IFBLK 0060000 /* block special */ +#define _IFREG 0100000 /* regular */ +#define _IFLNK 0120000 /* symbolic link */ +#define _IFSOCK 0140000 /* socket */ +#define _IFIFO 0010000 /* fifo */ + +struct fs_node; + +typedef uint32_t (*read_type_t) (struct fs_node *, uint32_t, uint32_t, uint8_t *); +typedef uint32_t (*write_type_t) (struct fs_node *, uint32_t, uint32_t, uint8_t *); +typedef void (*open_type_t) (struct fs_node *, unsigned int flags); +typedef void (*close_type_t) (struct fs_node *); +typedef struct dirent *(*readdir_type_t) (struct fs_node *, uint32_t); +typedef struct fs_node *(*finddir_type_t) (struct fs_node *, char *name); +typedef void (*create_type_t) (struct fs_node *, char *name, uint16_t permission); +typedef void (*unlink_type_t) (struct fs_node *, char *name); +typedef void (*mkdir_type_t) (struct fs_node *, char *name, uint16_t permission); +typedef int (*ioctl_type_t) (struct fs_node *, int request, void * argp); +typedef int (*get_size_type_t) (struct fs_node *); +typedef int (*chmod_type_t) (struct fs_node *, int mode); +typedef void (*symlink_type_t) (struct fs_node *, char * name, char * value); +typedef int (*readlink_type_t) (struct fs_node *, char * buf, size_t size); +typedef int (*selectcheck_type_t) (struct fs_node *); +typedef int (*selectwait_type_t) (struct fs_node *, void * process); +typedef int (*chown_type_t) (struct fs_node *, int, int); + +typedef struct fs_node { + char name[256]; /* The filename. */ + void * device; /* Device object (optional) */ + uint32_t mask; /* The permissions mask. */ + uint32_t uid; /* The owning user. */ + uint32_t gid; /* The owning group. */ + uint32_t flags; /* Flags (node type, etc). */ + uint32_t inode; /* Inode number. */ + uint32_t length; /* Size of the file, in byte. */ + uint32_t impl; /* Used to keep track which fs it belongs to. */ + uint32_t open_flags; /* Flags passed to open (read/write/append, etc.) */ + + /* times */ + uint32_t atime; /* Accessed */ + uint32_t mtime; /* Modified */ + uint32_t ctime; /* Created */ + + /* File operations */ + read_type_t read; + write_type_t write; + open_type_t open; + close_type_t close; + readdir_type_t readdir; + finddir_type_t finddir; + create_type_t create; + mkdir_type_t mkdir; + ioctl_type_t ioctl; + get_size_type_t get_size; + chmod_type_t chmod; + unlink_type_t unlink; + symlink_type_t symlink; + readlink_type_t readlink; + + struct fs_node *ptr; /* Alias pointer, for symlinks. */ + uint32_t offset; /* Offset for read operations XXX move this to new "file descriptor" entry */ + int32_t refcount; + uint32_t nlink; + + selectcheck_type_t selectcheck; + selectwait_type_t selectwait; + + chown_type_t chown; +} fs_node_t; + +struct dirent { + uint32_t ino; /* Inode number. */ + char name[256]; /* The filename. */ +}; + +struct stat { + uint16_t st_dev; + uint16_t st_ino; + uint32_t st_mode; + uint16_t st_nlink; + uint16_t st_uid; + uint16_t st_gid; + uint16_t st_rdev; + uint32_t st_size; + uint32_t st_atime; + uint32_t __unused1; + uint32_t st_mtime; + uint32_t __unused2; + uint32_t st_ctime; + uint32_t __unused3; + uint32_t st_blksize; + uint32_t st_blocks; +}; + +struct vfs_entry { + char * name; + fs_node_t * file; + char * device; + char * fs_type; +}; + +extern fs_node_t *fs_root; +extern int pty_create(void *size, fs_node_t ** fs_master, fs_node_t ** fs_slave); + +int has_permission(fs_node_t *node, int permission_bit); +uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +void open_fs(fs_node_t *node, unsigned int flags); +void close_fs(fs_node_t *node); +struct dirent *readdir_fs(fs_node_t *node, uint32_t index); +fs_node_t *finddir_fs(fs_node_t *node, char *name); +int mkdir_fs(char *name, uint16_t permission); +int create_file_fs(char *name, uint16_t permission); +fs_node_t *kopen(char *filename, uint32_t flags); +char *canonicalize_path(char *cwd, char *input); +fs_node_t *clone_fs(fs_node_t * source); +int ioctl_fs(fs_node_t *node, int request, void * argp); +int chmod_fs(fs_node_t *node, int mode); +int chown_fs(fs_node_t *node, int uid, int gid); +int unlink_fs(char * name); +int symlink_fs(char * value, char * name); +int readlink_fs(fs_node_t * node, char * buf, size_t size); +int selectcheck_fs(fs_node_t * node); +int selectwait_fs(fs_node_t * node, void * process); + +void vfs_install(void); +void * vfs_mount(char * path, fs_node_t * local_root); +typedef fs_node_t * (*vfs_mount_callback)(char * arg, char * mount_point); +int vfs_register(char * name, vfs_mount_callback callback); +int vfs_mount_type(char * type, char * arg, char * mountpoint); +void vfs_lock(fs_node_t * node); + +/* Debug purposes only, please */ +void debug_print_vfs_tree(void); + +void map_vfs_directory(char *); + +int make_unix_pipe(fs_node_t ** pipes); + diff --git a/kernel/include/hashmap.h b/kernel/include/hashmap.h new file mode 100644 index 00000000..ccac4afd --- /dev/null +++ b/kernel/include/hashmap.h @@ -0,0 +1,47 @@ +#pragma once + +#include "list.h" + +#ifdef _KERNEL_ +# include +#else +# include +# include +# include +#endif + +typedef unsigned int (*hashmap_hash_t) (void * key); +typedef int (*hashmap_comp_t) (void * a, void * b); +typedef void (*hashmap_free_t) (void *); +typedef void * (*hashmap_dupe_t) (void *); + +typedef struct hashmap_entry { + char * key; + void * value; + struct hashmap_entry * next; +} hashmap_entry_t; + +typedef struct hashmap { + hashmap_hash_t hash_func; + hashmap_comp_t hash_comp; + hashmap_dupe_t hash_key_dup; + hashmap_free_t hash_key_free; + hashmap_free_t hash_val_free; + size_t size; + hashmap_entry_t ** entries; +} hashmap_t; + +hashmap_t * hashmap_create(int size); +hashmap_t * hashmap_create_int(int size); +void * hashmap_set(hashmap_t * map, void * key, void * value); +void * hashmap_get(hashmap_t * map, void * key); +void * hashmap_remove(hashmap_t * map, void * key); +int hashmap_has(hashmap_t * map, void * key); +list_t * hashmap_keys(hashmap_t * map); +list_t * hashmap_values(hashmap_t * map); +void hashmap_free(hashmap_t * map); + +unsigned int hashmap_string_hash(void * key); +int hashmap_string_comp(void * a, void * b); +void * hashmap_string_dupe(void * key); + diff --git a/kernel/include/ioctl.h b/kernel/include/ioctl.h new file mode 120000 index 00000000..4712af1b --- /dev/null +++ b/kernel/include/ioctl.h @@ -0,0 +1 @@ +../../include/sys/ioctl.h \ No newline at end of file diff --git a/kernel/include/ipv4.h b/kernel/include/ipv4.h new file mode 100644 index 00000000..61de0c37 --- /dev/null +++ b/kernel/include/ipv4.h @@ -0,0 +1,188 @@ +#pragma once + +#include + +struct ethernet_packet { + uint8_t destination[6]; + uint8_t source[6]; + uint16_t type; + uint8_t payload[]; +} __attribute__((packed)); + +struct ipv4_packet { + uint8_t version_ihl; + uint8_t dscp_ecn; + uint16_t length; + uint16_t ident; + uint16_t flags_fragment; + uint8_t ttl; + uint8_t protocol; + uint16_t checksum; + uint32_t source; + uint32_t destination; + uint8_t payload[]; +} __attribute__ ((packed)); + +struct udp_packet { + uint16_t source_port; + uint16_t destination_port; + uint16_t length; + uint16_t checksum; + uint8_t payload[]; +} __attribute__ ((packed)); + +struct dhcp_packet { + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + + uint32_t xid; + + uint16_t secs; + uint16_t flags; + + uint32_t ciaddr; + uint32_t yiaddr; + uint32_t siaddr; + uint32_t giaddr; + + uint8_t chaddr[16]; + + uint8_t sname[64]; + uint8_t file[128]; + + uint32_t magic; + + uint8_t options[]; +} __attribute__ ((packed)); + +struct dns_packet { + uint16_t qid; + uint16_t flags; + uint16_t questions; + uint16_t answers; + uint16_t authorities; + uint16_t additional; + uint8_t data[]; +} __attribute__ ((packed)); + +struct tcp_header { + uint16_t source_port; + uint16_t destination_port; + + uint32_t seq_number; + uint32_t ack_number; + + uint16_t flags; + uint16_t window_size; + uint16_t checksum; + uint16_t urgent; + + uint8_t payload[]; +} __attribute__((packed)); + +struct tcp_check_header { + uint32_t source; + uint32_t destination; + uint8_t zeros; + uint8_t protocol; + uint16_t tcp_len; + uint8_t tcp_header[]; +}; + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 + +// Note: Data offset is in upper 4 bits of flags field. Shift and subtract 5 since that is the min TCP size. +// If the value is more than 5, multiply by 4 because this field is specified in number of words +#define TCP_OPTIONS_LENGTH(tcp) (((((tcp)->flags) >> 12) - 5) * 4) +#define TCP_HEADER_LENGTH(tcp) ((((tcp)->flags) >> 12) * 4) +#define TCP_HEADER_LENGTH_FLIPPED(tcp) (((htons((tcp)->flags)) >> 12) * 4) + +#define htonl(l) ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24)) +#define htons(s) ( (((s) & 0xFF) << 8) | (((s) & 0xFF00) >> 8) ) +#define ntohl(l) htonl((l)) +#define ntohs(s) htons((s)) + +#define BROADCAST_MAC {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} +#define IPV4_PROT_UDP 17 +#define IPV4_PROT_TCP 6 +#define DHCP_MAGIC 0x63825363 + +#define TCP_FLAGS_FIN (1 << 0) +#define TCP_FLAGS_SYN (1 << 1) +#define TCP_FLAGS_RES (1 << 2) +#define TCP_FLAGS_PSH (1 << 3) +#define TCP_FLAGS_ACK (1 << 4) +#define TCP_FLAGS_URG (1 << 5) +#define TCP_FLAGS_ECE (1 << 6) +#define TCP_FLAGS_CWR (1 << 7) +#define TCP_FLAGS_NS (1 << 8) +#define DATA_OFFSET_5 (0x5 << 12) + +#define ETHERNET_TYPE_IPV4 0x0800 +#define ETHERNET_TYPE_ARP 0x0806 + +extern uint32_t ip_aton(const char * in); +extern void ip_ntoa(uint32_t src_addr, char * out); +extern uint16_t calculate_ipv4_checksum(struct ipv4_packet * p); +uint16_t calculate_tcp_checksum(struct tcp_check_header * p, struct tcp_header * h, void * d, size_t d_words); + +struct tcp_socket { + list_t* is_connected; + uint32_t seq_no; + uint32_t ack_no; + int status; +}; + +// Note: for now, not sure what to put in here, so removing from the union to get rid of compiler warnings about empty struct +// struct udp_socket { +// }; + +struct socket { + uint32_t ip; + uint8_t mac[6]; + uint32_t port_dest; + uint32_t port_recv; + list_t* packet_queue; + spin_lock_t packet_queue_lock; + list_t* packet_wait; + int32_t status; + size_t bytes_available; + size_t bytes_read; + void * current_packet; + uint32_t sock_type; + union { + struct tcp_socket tcp_socket; + // struct udp_socket udp_socket; + } proto_sock; + list_t * alert_waiters; +}; + +struct sized_blob { + size_t size; + uint8_t blob[]; +}; + +struct in_addr { + unsigned long s_addr; // load with inet_pton() +}; + +struct sockaddr { + uint16_t sa_family; + char sa_data[14]; +}; + +struct sockaddr_in { + short sin_family; // e.g. AF_INET, AF_INET6 + unsigned short sin_port; // e.g. htons(3490) + struct in_addr sin_addr; // see struct in_addr, below + char sin_zero[8]; // zero this if you want to +}; + +typedef struct { + uint8_t *payload; + size_t payload_size; +} tcpdata_t; + diff --git a/kernel/include/libc.h b/kernel/include/libc.h new file mode 100644 index 00000000..de740a88 --- /dev/null +++ b/kernel/include/libc.h @@ -0,0 +1,37 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once + +#include + +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define MAX(A, B) ((A) > (B) ? (A) : (B)) + +extern void * memcpy(void * restrict dest, const void * restrict src, size_t n); +extern void * memset(void * dest, int c, size_t n); +extern void * memchr(const void * src, int c, size_t n); +extern void * memrchr(const void * m, int c, size_t n); +extern void * memmove(void *dest, const void *src, size_t n); + +extern int memcmp(const void *vl, const void *vr, size_t n); + +extern char * strdup(const char * s); +extern char * stpcpy(char * restrict d, const char * restrict s); +extern char * strcpy(char * restrict dest, const char * restrict src); +extern char * strchrnul(const char * s, int c); +extern char * strchr(const char * s, int c); +extern char * strrchr(const char * s, int c); +extern char * strpbrk(const char * s, const char * b); +extern char * strstr(const char * h, const char * n); + +extern int strcmp(const char * l, const char * r); + +extern size_t strcspn(const char * s, const char * c); +extern size_t strspn(const char * s, const char * c); +extern size_t strlen(const char * s); + +extern int atoi(const char * s); + +/* Non-standard broken strtok_r */ +extern char * strtok_r(char * str, const char * delim, char ** saveptr); + diff --git a/kernel/include/list.h b/kernel/include/list.h new file mode 100644 index 00000000..c1840138 --- /dev/null +++ b/kernel/include/list.h @@ -0,0 +1,50 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * General-purpose list implementations. + */ +#pragma once + +#ifdef _KERNEL_ +# include +#else +# include +# include +# include +#endif + +typedef struct node { + struct node * next; + struct node * prev; + void * value; + void * owner; +} __attribute__((packed)) node_t; + +typedef struct { + node_t * head; + node_t * tail; + size_t length; +} __attribute__((packed)) list_t; + +void list_destroy(list_t * list); +void list_free(list_t * list); +void list_append(list_t * list, node_t * item); +node_t * list_insert(list_t * list, void * item); +list_t * list_create(void); +node_t * list_find(list_t * list, void * value); +int list_index_of(list_t * list, void * value); +void list_remove(list_t * list, size_t index); +void list_delete(list_t * list, node_t * node); +node_t * list_pop(list_t * list); +node_t * list_dequeue(list_t * list); +list_t * list_copy(list_t * original); +void list_merge(list_t * target, list_t * source); + +void list_append_after(list_t * list, node_t * before, node_t * node); +node_t * list_insert_after(list_t * list, node_t * before, void * item); + +void list_append_before(list_t * list, node_t * after, node_t * node); +node_t * list_insert_before(list_t * list, node_t * after, void * item); + +#define foreach(i, list) for (node_t * i = (list)->head; i != NULL; i = i->next) +#define foreachr(i, list) for (node_t * i = (list)->tail; i != NULL; i = i->prev) + diff --git a/kernel/include/logging.h b/kernel/include/logging.h new file mode 100644 index 00000000..5576e68a --- /dev/null +++ b/kernel/include/logging.h @@ -0,0 +1,27 @@ +#pragma once + +typedef enum { + INFO = 0, /* Unimportant */ + NOTICE, /* Important, but not bad */ + WARNING, /* Not what was expected, but still okay */ + ERROR, /* This is bad... */ + CRITICAL, /* Shit */ + INSANE +} log_type_t; + +extern log_type_t debug_level; +extern void * debug_file; +extern void _debug_print(char * title, int line_no, log_type_t level, char *fmt, ...); +extern void (*debug_hook)(void *, char *); +extern void (*debug_video_crash)(char **); + +#ifndef MODULE_NAME +#define MODULE_NAME __FILE__ +#endif + +#ifndef QUIET +#define debug_print(level, ...) _debug_print(MODULE_NAME, __LINE__, level, __VA_ARGS__) +#else +#define debug_print(level, ...) +#endif + diff --git a/kernel/include/mem.h b/kernel/include/mem.h new file mode 100644 index 00000000..cb7c9894 --- /dev/null +++ b/kernel/include/mem.h @@ -0,0 +1,16 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ + +#pragma once + +#include + +extern uintptr_t heap_end; + +extern void set_frame(uintptr_t frame_addr); +extern void clear_frame(uintptr_t frame_addr); +extern uint32_t test_frame(uintptr_t frame_addr); +extern uint32_t first_frame(void); + +extern uintptr_t map_to_physical(uintptr_t virtual); + diff --git a/kernel/include/mod/net.h b/kernel/include/mod/net.h new file mode 100644 index 00000000..ec674385 --- /dev/null +++ b/kernel/include/mod/net.h @@ -0,0 +1,32 @@ +#ifndef KERNEL_MOD_NET_H +#define KERNEL_MOD_NET_H + +typedef uint8_t* (*get_mac_func)(void); +typedef struct ethernet_packet* (*get_packet_func)(void); +typedef void (*send_packet_func)(uint8_t*, size_t); + +struct netif { + void *extra; + + get_mac_func get_mac; + get_packet_func get_packet; + send_packet_func send_packet; + + uint8_t hwaddr[6]; + uint32_t source; + + char * driver; + + uint32_t gateway; +}; + +extern void init_netif_funcs(get_mac_func mac_func, get_packet_func get_func, send_packet_func send_func, char * device); +extern void net_handler(void * data, char * name); +extern size_t write_dhcp_packet(uint8_t * buffer); + +extern struct socket* net_open(uint32_t type); +extern int net_send(struct socket* socket, uint8_t* payload, size_t payload_size, int flags); +extern size_t net_recv(struct socket* socket, uint8_t* buffer, size_t len); +extern int net_connect(struct socket* socket, uint32_t dest_ip, uint16_t dest_port); +extern int net_close(struct socket* socket); +#endif diff --git a/kernel/include/mod/rtl.h b/kernel/include/mod/rtl.h new file mode 100644 index 00000000..5cab0a00 --- /dev/null +++ b/kernel/include/mod/rtl.h @@ -0,0 +1,4 @@ +#ifndef KERNEL_MOD_RTL_H +#define KERNEL_MOD_RTL_H + +#endif diff --git a/kernel/include/mod/shell.h b/kernel/include/mod/shell.h new file mode 100644 index 00000000..a83c795b --- /dev/null +++ b/kernel/include/mod/shell.h @@ -0,0 +1,34 @@ +#ifndef KERNEL_MOD_SHELL_H +#define KERNEL_MOD_SHELL_H + +#include + +/* + * We're going to have a list of shell commands. + * We'll search through it linearly because I don't + * care to write a hashmap right now. Maybe later. + */ +struct shell_command { + char * name; + int (*function) (fs_node_t * tty, int argc, char * argv[]); + char * description; +}; + +extern void debug_shell_install(struct shell_command * sh); +extern int debug_shell_readline(fs_node_t * dev, char * linebuf, int max); +extern void tty_set_buffered(fs_node_t * dev); +extern void tty_set_unbuffered(fs_node_t * dev); + +#define DEFINE_SHELL_FUNCTION(n, desc) \ + static int shell_ ## n (fs_node_t * tty, int argc, char * argv[]); \ + static struct shell_command shell_ ## n ## _desc = { \ + .name = #n , \ + .function = &shell_ ## n , \ + .description = desc \ + }; \ + static int shell_ ## n (fs_node_t * tty, int argc, char * argv[]) + +#define BIND_SHELL_FUNCTION(name) \ + debug_shell_install(&shell_ ## name ## _desc); + +#endif diff --git a/kernel/include/mod/snd.h b/kernel/include/mod/snd.h new file mode 100644 index 00000000..11c86647 --- /dev/null +++ b/kernel/include/mod/snd.h @@ -0,0 +1,52 @@ +#ifndef KERNEL_MOD_SND_H +#define KERNEL_MOD_SND_H + +/* The format isn't really used for anything right now */ +#define SND_FORMAT_L16SLE 0 /* Linear 16-bit signed little endian */ + +#include +#include +#include + +#define SND_KNOB_VENDOR 1024 + +typedef uint16_t snd_mixer_enum_t; + +typedef struct snd_knob { + char name[SND_KNOB_NAME_SIZE]; + uint32_t id; +} snd_knob_t; + +typedef struct snd_device { + char name[256]; /* Name of the device. */ + void * device; /* Private data for the device. May be NULL. */ + uint32_t playback_speed; /* Playback speed in Hz */ + uint32_t playback_format; /* Playback format (SND_FORMAT_*) */ + + snd_knob_t *knobs; + uint32_t num_knobs; + int (*mixer_read)(uint32_t knob_id, uint32_t *val); + int (*mixer_write)(uint32_t knob_id, uint32_t val); + + uint32_t id; +} snd_device_t; + +/* + * Register a device to be used with snd + */ +int snd_register(snd_device_t * device); + +/* + * Unregister a device + */ +int snd_unregister(snd_device_t * device); + +/* + * Request a buffer to play from snd. This is to be called from the device in + * order to fill a buffer on demand. After the call the buffer is garaunteed + * to be filled to the size requested even if that means writing zeroes for + * when there are no other samples. + */ +int snd_request_buf(snd_device_t * device, uint32_t size, uint8_t *buffer); + +#endif /* KERNEL_MOD_SND_H */ diff --git a/kernel/include/mod/sound.h b/kernel/include/mod/sound.h new file mode 100644 index 00000000..1fa8e8a2 --- /dev/null +++ b/kernel/include/mod/sound.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#define SND_MAX_KNOBS 256 +#define SND_KNOB_NAME_SIZE 256 +#define SND_KNOB_MAX_VALUE UINT32_MAX + +#define SND_KNOB_MASTER 0 +#define SND_DEVICE_MAIN 0 + +typedef struct snd_knob_list { + uint32_t device; /* IN */ + uint32_t num; /* OUT */ + uint32_t ids[SND_MAX_KNOBS]; /* OUT */ +} snd_knob_list_t; + +typedef struct snd_knob_info { + uint32_t device; /* IN */ + uint32_t id; /* IN */ + char name[SND_KNOB_NAME_SIZE]; /* OUT */ +} snd_knob_info_t; + +typedef struct snd_knob_value { + uint32_t device; /* IN */ + uint32_t id; /* IN */ + uint32_t val; /* OUT for SND_MIXER_READ_KNOB, IN for SND_MIXER_WRITE_KNOB */ +} snd_knob_value_t; + + +/* IOCTLs */ +#define SND_MIXER_GET_KNOBS 0 +#define SND_MIXER_GET_KNOB_INFO 1 +#define SND_MIXER_READ_KNOB 2 +#define SND_MIXER_WRITE_KNOB 3 + diff --git a/kernel/include/mod/tmpfs.h b/kernel/include/mod/tmpfs.h new file mode 100644 index 00000000..ddd9aa74 --- /dev/null +++ b/kernel/include/mod/tmpfs.h @@ -0,0 +1,38 @@ +#ifndef _TMPFS_H__ +#define _TMPFS_H__ +#include + +fs_node_t * tmpfs_create(char * name); + +struct tmpfs_file { + char * name; + int type; + int mask; + int uid; + int gid; + unsigned int atime; + unsigned int mtime; + unsigned int ctime; + size_t length; + size_t block_count; + size_t pointers; + char ** blocks; + char * target; +}; + +struct tmpfs_dir; + +struct tmpfs_dir { + char * name; + int type; + int mask; + int uid; + int gid; + unsigned int atime; + unsigned int mtime; + unsigned int ctime; + list_t * files; + struct tmpfs_dir * parent; +}; + +#endif /* _TMPFS_H__ */ diff --git a/kernel/include/module.h b/kernel/include/module.h new file mode 100644 index 00000000..4468bc8d --- /dev/null +++ b/kernel/include/module.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +typedef struct { + char * name; + int (* initialize)(void); + int (* finalize)(void); +} module_defs; + +typedef struct { + module_defs * mod_info; + void * bin_data; + hashmap_t * symbols; + uintptr_t end; + size_t deps_length; + char * deps; +} module_data_t; + +void (* symbol_find(const char * name))(void); + +extern int module_quickcheck(void * blob); +extern void * module_load_direct(void * blob, size_t size); +extern void * module_load(char * filename); +extern void module_unload(char * name); +extern void modules_install(void); + +#define MODULE_DEF(n,init,fini) \ + module_defs module_info_ ## n = { \ + .name = #n, \ + .initialize = &init, \ + .finalize = &fini \ + } + +extern hashmap_t * modules_get_list(void); +extern hashmap_t * modules_get_symbols(void); + +#define MODULE_DEPENDS(n) \ + static char _mod_dependency_ ## n [] __attribute__((section("moddeps"), used)) = #n + diff --git a/kernel/include/mouse.h b/kernel/include/mouse.h new file mode 100644 index 00000000..45138390 --- /dev/null +++ b/kernel/include/mouse.h @@ -0,0 +1,20 @@ +#pragma once + +typedef enum { + LEFT_CLICK = 0x01, + RIGHT_CLICK = 0x02, + MIDDLE_CLICK = 0x04, + + MOUSE_SCROLL_UP = 0x10, + MOUSE_SCROLL_DOWN = 0x20, +} mouse_click_t; + +typedef struct { + uint32_t magic; + int32_t x_difference; + int32_t y_difference; + mouse_click_t buttons; +} mouse_device_packet_t; + +#define MOUSE_MAGIC 0xFEED1234 + diff --git a/kernel/include/multiboot.h b/kernel/include/multiboot.h new file mode 100644 index 00000000..5cf26ec9 --- /dev/null +++ b/kernel/include/multiboot.h @@ -0,0 +1,92 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once + +#include + +#define MULTIBOOT_MAGIC 0x1BADB002 +#define MULTIBOOT_EAX_MAGIC 0x2BADB002 +#define MULTIBOOT_FLAG_MEM 0x001 +#define MULTIBOOT_FLAG_DEVICE 0x002 +#define MULTIBOOT_FLAG_CMDLINE 0x004 +#define MULTIBOOT_FLAG_MODS 0x008 +#define MULTIBOOT_FLAG_AOUT 0x010 +#define MULTIBOOT_FLAG_ELF 0x020 +#define MULTIBOOT_FLAG_MMAP 0x040 +#define MULTIBOOT_FLAG_CONFIG 0x080 +#define MULTIBOOT_FLAG_LOADER 0x100 +#define MULTIBOOT_FLAG_APM 0x200 +#define MULTIBOOT_FLAG_VBE 0x400 + +struct multiboot +{ + uintptr_t flags; + uintptr_t mem_lower; + uintptr_t mem_upper; + uintptr_t boot_device; + uintptr_t cmdline; + uintptr_t mods_count; + uintptr_t mods_addr; + uintptr_t num; + uintptr_t size; + uintptr_t addr; + uintptr_t shndx; + uintptr_t mmap_length; + uintptr_t mmap_addr; + uintptr_t drives_length; + uintptr_t drives_addr; + uintptr_t config_table; + uintptr_t boot_loader_name; + uintptr_t apm_table; + uintptr_t vbe_control_info; + uintptr_t vbe_mode_info; + uintptr_t vbe_mode; + uintptr_t vbe_interface_seg; + uintptr_t vbe_interface_off; + uintptr_t vbe_interface_len; +} __attribute__ ((packed)); + +typedef struct { + uint16_t attributes; + uint8_t winA, winB; + uint16_t granularity; + uint16_t winsize; + uint16_t segmentA, segmentB; + uint32_t realFctPtr; + uint16_t pitch; + + uint16_t Xres, Yres; + uint8_t Wchar, Ychar, planes, bpp, banks; + uint8_t memory_model, bank_size, image_pages; + uint8_t reserved0; + + uint8_t red_mask, red_position; + uint8_t green_mask, green_position; + uint8_t blue_mask, blue_position; + uint8_t rsv_mask, rsv_position; + uint8_t directcolor_attributes; + + uint32_t physbase; + uint32_t reserved1; + uint16_t reserved2; +} __attribute__ ((packed)) vbe_info_t; + +typedef struct { + uintptr_t mod_start; + uintptr_t mod_end; + uintptr_t cmdline; + uintptr_t reserved; +} __attribute__ ((packed)) mboot_mod_t; + +typedef struct { + uint32_t size; + uint64_t base_addr; + uint64_t length; + uint32_t type; +} __attribute__ ((packed)) mboot_memmap_t; + +extern struct multiboot *copy_multiboot(struct multiboot *mboot_ptr); +extern void dump_multiboot(struct multiboot *mboot_ptr); +extern char * ramdisk; +extern struct multiboot * mboot_ptr; + diff --git a/kernel/include/pci.h b/kernel/include/pci.h new file mode 100644 index 00000000..613e884b --- /dev/null +++ b/kernel/include/pci.h @@ -0,0 +1,69 @@ +#pragma once + +#define PCI_VENDOR_ID 0x00 // 2 +#define PCI_DEVICE_ID 0x02 // 2 +#define PCI_COMMAND 0x04 // 2 +#define PCI_STATUS 0x06 // 2 +#define PCI_REVISION_ID 0x08 // 1 + +#define PCI_PROG_IF 0x09 // 1 +#define PCI_SUBCLASS 0x0a // 1 +#define PCI_CLASS 0x0b // 1 +#define PCI_CACHE_LINE_SIZE 0x0c // 1 +#define PCI_LATENCY_TIMER 0x0d // 1 +#define PCI_HEADER_TYPE 0x0e // 1 +#define PCI_BIST 0x0f // 1 +#define PCI_BAR0 0x10 // 4 +#define PCI_BAR1 0x14 // 4 +#define PCI_BAR2 0x18 // 4 +#define PCI_BAR3 0x1C // 4 +#define PCI_BAR4 0x20 // 4 +#define PCI_BAR5 0x24 // 4 + +#define PCI_INTERRUPT_LINE 0x3C // 1 + +#define PCI_SECONDARY_BUS 0x19 // 1 + +#define PCI_HEADER_TYPE_DEVICE 0 +#define PCI_HEADER_TYPE_BRIDGE 1 +#define PCI_HEADER_TYPE_CARDBUS 2 + +#define PCI_TYPE_BRIDGE 0x0604 +#define PCI_TYPE_SATA 0x0106 + +#define PCI_ADDRESS_PORT 0xCF8 +#define PCI_VALUE_PORT 0xCFC + +#define PCI_NONE 0xFFFF + +typedef void (*pci_func_t)(uint32_t device, uint16_t vendor_id, uint16_t device_id, void * extra); + +static inline int pci_extract_bus(uint32_t device) { + return (uint8_t)((device >> 16)); +} +static inline int pci_extract_slot(uint32_t device) { + return (uint8_t)((device >> 8)); +} +static inline int pci_extract_func(uint32_t device) { + return (uint8_t)(device); +} + +static inline uint32_t pci_get_addr(uint32_t device, int field) { + return 0x80000000 | (pci_extract_bus(device) << 16) | (pci_extract_slot(device) << 11) | (pci_extract_func(device) << 8) | ((field) & 0xFC); +} + +static inline uint32_t pci_box_device(int bus, int slot, int func) { + return (uint32_t)((bus << 16) | (slot << 8) | func); +} + +uint32_t pci_read_field(uint32_t device, int field, int size); +void pci_write_field(uint32_t device, int field, int size, uint32_t value); +uint16_t pci_find_type(uint32_t dev); +const char * pci_vendor_lookup(unsigned short vendor_id); +const char * pci_device_lookup(unsigned short vendor_id, unsigned short device_id); +void pci_scan_hit(pci_func_t f, uint32_t dev, void * extra); +void pci_scan_func(pci_func_t f, int type, int bus, int slot, int func, void * extra); +void pci_scan_slot(pci_func_t f, int type, int bus, int slot, void * extra); +void pci_scan_bus(pci_func_t f, int type, int bus, void * extra); +void pci_scan(pci_func_t f, int type, void * extra); + diff --git a/kernel/include/pci_list.h b/kernel/include/pci_list.h new file mode 100644 index 00000000..c1f480cd --- /dev/null +++ b/kernel/include/pci_list.h @@ -0,0 +1,7057 @@ + + +#if 0 + +PCIHDR.H: PCI Vendors, Devices, and Class Type information + +Created automatically from the web using the following URL: +http://pcidatabase.com/ +Software to create and maintain the PCICODE List written by: +Jim Boemler (jboemler@halcyon.com) + + This header created on Fri Jan 16 09:49:40 PST 2009 + +Too many people have contributed to this list to acknowledge them all, but +a few have provided the majority of the input and deserve special mention: + Frederic Potter, who maintains a list for Linux. + Chris Aston at Madge Networks. + Thomas Dippon of Hewlett-Packard GmbH. + Jurgen ("Josh") Thelen + William H. Avery III at Altitech + Sergei Shtylyov of Brain-dead Software in Russia +#endif + +// NOTE that the 0xFFFF of 0xFF entries at the end of some tables below are +// not properly list terminators, but are actually the printable definitions +// of values that are legitimately found on the PCI bus. The size +// definitions should be used for loop control when the table is searched. + +typedef struct _PCI_VENTABLE +{ + unsigned short VenId ; + const char * VenShort ; + const char * VenFull ; +} PCI_VENTABLE, *PPCI_VENTABLE ; + +PCI_VENTABLE PciVenTable [] = +{ + { 0x0033, "", "Paradyne Corp." } , + { 0x003D, "well", "master" } , + { 0x0070, "Hauppauge1", "Hauppauge Computer Works Inc." } , + { 0x0100, "ncipher", "Ncipher Corp. Ltd" } , + { 0x0123, "", "General Dynamics" } , + { 0x0315, "", "SK - Electronics Co., Ltd." } , + { 0x0A89, "BREA", "BREA Technologies Inc." } , + { 0x0E11, "Compaq", "Compaq Computer Corp." } , + { 0x1000, "LSI", "LSI Logic" } , + { 0x1001, "KOLTER", "Kolter Electronic - Germany" } , + { 0x1002, "ATI", "ATI Technologies Inc." } , + { 0x1003, "ULSI", "ULSI" } , + { 0x1004, "VLSI", "VLSI Technology" } , + { 0x1006, "Reply", "Reply Group" } , + { 0x1007, "NetFrame", "Netframe Systems Inc." } , + { 0x1008, "Epson", "Epson" } , + { 0x100A, "Phoenix", "Phoenix Technologies Ltd." } , + { 0x100B, "NSC", "National Semiconductors" } , + { 0x100C, "Tseng", "Tseng Labs" } , + { 0x100D, "AST", "AST Research" } , + { 0x100E, "Weitek", "Weitek" } , + { 0x1010, "VLogic", "Video Logic Ltd." } , + { 0x1011, "DEC", "Digital Equipment Corporation" } , + { 0x1012, "Micronics", "Micronics Computers Inc." } , + { 0x1013, "Cirrus", "Cirrus Logic" } , + { 0x1014, "IBM", "International Business Machines Corp." } , + { 0x1016, "Fujitsu ICL", "Fujitsu ICL Computers" } , + { 0x1017, "Spea", "Spea Software AG" } , + { 0x1018, "Unisys", "Unisys Systems" } , + { 0x1019, "ECS", "Elitegroup Computer System" } , + { 0x101A, "NCR", "NCR Corporation" } , + { 0x101B, "Vitesse", "Vitesse Semiconductor" } , + { 0x101E, "AMI", "American Megatrends Inc." } , + { 0x101F, "PictureTel", "PictureTel Corp." } , + { 0x1020, "Hitachi", "Hitachi Computer Electronics" } , + { 0x1021, "OKI", "Oki Electric Industry" } , + { 0x1022, "AMD", "Advanced Micro Devices" } , + { 0x1023, "machdo", "TRIDENT MICRO" } , + { 0x1025, "Acer", "Acer Incorporated" } , + { 0x1028, "Dell", "Dell Computer Corporation" } , + { 0x102A, "LSI", "LSI Logic Headland Division" } , + { 0x102B, "Matrox", "Matrox Electronic Systems Ltd." } , + { 0x102C, "C&T", "Asiliant (Chips And Technologies)" } , + { 0x102D, "Wyse", "Wyse Technologies" } , + { 0x102E, "Olivetti", "Olivetti Advanced Technology" } , + { 0x102F, "A305-S6829", "Toshiba America" } , + { 0x1030, "TMC", "TMC Research" } , + { 0x1031, "miro", "miro Computer Products AG" } , + { 0x1033, "NEC", "NEC Electronics" } , + { 0x1034, "Burndy", "Burndy Corporation" } , + { 0x1036, "FDomain", "Future Domain" } , + { 0x1037, "Hitachi", "Hitachi Micro Systems Inc" } , + { 0x1038, "AMP", "AMP Incorporated" } , + { 0x1039, "SiS 630", "Silicon Integrated Systems" } , + { 0x103A, "Seiko", "Seiko Epson Corporation" } , + { 0x103B, "Tatung", "Tatung Corp. Of America" } , + { 0x103C, "HP", "Hewlett-Packard Company" } , + { 0x103E, "Solliday", "Solliday Engineering" } , + { 0x103F, "Logic Mod.", "Logic Modeling" } , + { 0x1041, "Computrend", "Computrend" } , + { 0x1043, "Asustek", "Asustek Computer Inc." } , + { 0x1044, "DPT", "Distributed Processing Tech" } , + { 0x1045, "OPTi", "OPTi Inc." } , + { 0x1046, "IPC", "IPC Corporation LTD" } , + { 0x1047, "Genoa", "Genoa Systems Corp." } , + { 0x1048, "ELSA", "ELSA GmbH" } , + { 0x1049, "Fountain", "Fountain Technology" } , + { 0x104A, "STM", "STMicroelectronics" } , + { 0x104B, "", "Mylex / Buslogic" } , + { 0x104C, "TI", "Texas Instruments" } , + { 0x104D, "Sony", "Sony Corporation" } , + { 0x104E, "Oak", "Oak Technology" } , + { 0x104F, "Co-Time", "Co-Time Computer Ltd." } , + { 0x1050, "Winbond", "Winbond Electronics Corp." } , + { 0x1051, "Anigma", "Anigma Corp." } , + { 0x1053, "Young", "Young Micro Systems" } , + { 0x1054, "Hitachi", "Hitachi Ltd" } , + { 0x1055, "SMSC", "Standard Microsystems Corp." } , + { 0x1056, "ICL", "ICL" } , + { 0x1057, "Motorola", "Motorola" } , + { 0x1058, "E&TR", "Electronics & Telecommunication Res" } , + { 0x1059, "Kontron", "Kontron Canada" } , + { 0x105A, "Promise", "Promise Technology" } , + { 0x105B, "Foxconn", "Foxconn International Inc." } , + { 0x105C, "Wipro", "Wipro Infotech Limited" } , + { 0x105D, "Number-Nine", "Number Nine Visual Technology" } , + { 0x105E, "Vtech", "Vtech Engineering Canada Ltd." } , + { 0x105F, "Infotronic", "Infotronic America Inc." } , + { 0x1060, "UMC", "United Microelectronics" } , + { 0x1061, "8x8", "8x8 Inc." } , + { 0x1062, "Maspar", "Maspar Computer Corp." } , + { 0x1063, "OOA", "Ocean Office Automation" } , + { 0x1064, "Alcatel", "Alcatel Cit" } , + { 0x1065, "TM", "Texas Microsystems" } , + { 0x1066, "Picopower", "Picopower Technology" } , + { 0x1067, "Mitsubishi", "Mitsubishi Electronics" } , + { 0x1068, "Div. Tech.", "Diversified Technology" } , + { 0x106A, "Aten", "Aten Research Inc." } , + { 0x106B, "Apple", "Power Mac G5 Quad" } , + { 0x106C, "Hyundai", "Hyundai Electronics America" } , + { 0x106D, "Sequent", "Sequent Computer Systems" } , + { 0x106E, "DFI", "DFI Inc." } , + { 0x106F, "CityGate", "City Gate Development LTD" } , + { 0x1070, "Daewoo", "Daewoo Telecom Ltd." } , + { 0x1071, "Mitac", "Mitac" } , + { 0x1072, "GIT", "GIT Co. Ltd." } , + { 0x1073, "Yamaha", "Yamaha Corporation" } , + { 0x1074, "Nexgen", "Nexgen Microsystems" } , + { 0x1075, "AIR", "Advanced Integration Research" } , + { 0x1077, "QLogic", "QLogic Corporation" } , + { 0x1078, "Cyrix", "Cyrix Corporation" } , + { 0x1079, "I-Bus", "I-Bus" } , + { 0x107A, "Networth", "Networth controls" } , + { 0x107B, "Gateway", "Gateway 2000" } , + { 0x107C, "Goldstar", "Goldstar Co. Ltd." } , + { 0x107D, "Leadtek", "Leadtek Research" } , + { 0x107E, "Interphase", "Testernec" } , + { 0x107F, "DTC", "Data Technology Corporation" } , + { 0x1080, "Cypress", "Cypress Semiconductor" } , + { 0x1081, "Radius Inc.", "Radius Inc." } , + { 0x1082, "EFA", "EFA Corporation Of America" } , + { 0x1083, "Forex", "Forex Computer Corporation" } , + { 0x1084, "Parador", "Parador" } , + { 0x1085, "Tulip", "Tulip Computers Int'l BV" } , + { 0x1086, "J. Bond", "J. Bond Computer Systems" } , + { 0x1087, "Cache", "Cache Computer" } , + { 0x1088, "MS Son.", "Microcomputer Systems (M) Son" } , + { 0x1089, "DG", "Data General Corporation" } , + { 0x108A, "Bit3", "SBS Operations" } , + { 0x108C, "Oakleigh", "Oakleigh Systems Inc." } , + { 0x108D, "Olicom", "Olicom" } , + { 0x108E, "Sun", "Sun Microsystems" } , + { 0x108F, "Systemsoft", "Systemsoft Corporation" } , + { 0x1090, "Encore", "Encore Computer Corporation" } , + { 0x1091, "Intergraph", "Intergraph Corporation" } , + { 0x1092, "Diamond", "Diamond Computer Systems" } , + { 0x1093, "Nat. Inst.", "National Instruments" } , + { 0x1094, "FIC", "First Int'l Computers" } , + { 0x1095, "Silicon Image", "Silicon Image, Inc." } , + { 0x1096, "Alacron", "Alacron" } , + { 0x1097, "Appian", "Appian Graphics" } , + { 0x1098, "Quantum", "Quantum Designs Ltd." } , + { 0x1099, "Samsung", "Samsung Electronics Co. Ltd." } , + { 0x109A, "Packard-Bell", "Packard Bell" } , + { 0x109B, "Gemlight", "Gemlight Computer Ltd." } , + { 0x109C, "Megachips", "Megachips Corporation" } , + { 0x109D, "Zida", "Zida Technologies Ltd." } , + { 0x109E, "Brooktree", "Brooktree Corporation" } , + { 0x109F, "Trigem", "Trigem Computer Inc." } , + { 0x10A0, "Meidensha", "Meidensha Corporation" } , + { 0x10A1, "Juko", "Juko Electronics Inc. Ltd." } , + { 0x10A2, "Quantum", "Quantum Corporation" } , + { 0x10A3, "Everex", "Everex Systems Inc." } , + { 0x10A4, "Globe", "Globe Manufacturing Sales" } , + { 0x10A5, "Racal", "Racal Interlan" } , + { 0x10A8, "Sierra", "Sierra Semiconductor" } , + { 0x10A9, "SG", "Silicon Graphics" } , + { 0x10AB, "Digicom", "Digicom" } , + { 0x10AC, "Honeywell", "Honeywell IASD" } , + { 0x10AD, "Winbond", "Winbond Systems Labs" } , + { 0x10AE, "Cornerstone", "Cornerstone Technology" } , + { 0x10AF, "MCS", "Micro Computer Systems Inc." } , + { 0x10B0, "CardExpert", "CardExpert Technology" } , + { 0x10B1, "Cabletron", "Cabletron Systems Inc." } , + { 0x10B2, "Raytheon", "Raytheon Company" } , + { 0x10B3, "Databook", "Databook Inc." } , + { 0x10B4, "STB", "STB Systems" } , + { 0x10B5, "PLX", "PLX Technology Inc." } , + { 0x10B6, "Madge", "Madge Networks" } , + { 0x10B7, "3Com", "3Com Corporation" } , + { 0x10B8, "SMC", "Standard Microsystems Corporation" } , + { 0x10B9, "Ali", "Ali Corporation" } , + { 0x10BA, "Mitsubishi", "Mitsubishi Electronics Corp." } , + { 0x10BB, "Dapha", "Dapha Electronics Corporation" } , + { 0x10BC, "ALR", "Advanced Logic Research Inc." } , + { 0x10BD, "Surecom", "Surecom Technology" } , + { 0x10BE, "Tseng", "Tsenglabs International Corp." } , + { 0x10BF, "MOST", "MOST Corp." } , + { 0x10C0, "Boca", "Boca Research Inc." } , + { 0x10C1, "ICM", "ICM Corp. Ltd." } , + { 0x10C2, "Auspex", "Auspex Systems Inc." } , + { 0x10C3, "Samsung", "Samsung Semiconductors" } , + { 0x10C4, "wim", "Award Software Int'l Inc." } , + { 0x10C5, "Xerox", "Xerox Corporation" } , + { 0x10C6, "Rambus", "Rambus Inc." } , + { 0x10C8, "Neomagic", "Neomagic Corporation" } , + { 0x10C9, "Dataexpert", "Dataexpert Corporation" } , + { 0x10CA, "Fujitsu", "Fujitsu Siemens" } , + { 0x10CB, "Omron", "Omron Corporation" } , + { 0x10CD, "AdvanSys", "Advanced System Products" } , + { 0x10CF, "Fujitsu", "Fujitsu Ltd." } , + { 0x10D1, "Future+", "Future+ Systems" } , + { 0x10D2, "Molex", "Molex Incorporated" } , + { 0x10D3, "Jabil", "Jabil Circuit Inc." } , + { 0x10D4, "Hualon", "Hualon Microelectronics" } , + { 0x10D5, "Autologic", "Autologic Inc." } , + { 0x10D6, "Wilson .co .ltd", "Wilson .co .ltd" } , + { 0x10D7, "BCM", "BCM Advanced Research" } , + { 0x10D8, "APL", "Advanced Peripherals Labs" } , + { 0x10D9, "Macronix", "Macronix International Co. Ltd." } , + { 0x10DB, "Rohm", "Rohm Research" } , + { 0x10DC, "CERN", "CERN-European Lab. for Particle Physics" } , + { 0x10DD, "E&S", "Evans & Sutherland" } , + { 0x10DE, "NVIDIA", "NVIDIA" } , + { 0x10DF, "Emulex", "Emulex Corporation" } , + { 0x10E1, "Tekram", "Tekram Technology Corp. Ltd." } , + { 0x10E2, "Aptix", "Aptix Corporation" } , + { 0x10E3, "Tundra", "Tundra Semiconductor Corp." } , + { 0x10E4, "Tandem", "Tandem Computers" } , + { 0x10E5, "MIC", "Micro Industries Corporation" } , + { 0x10E6, "Gainbery", "Gainbery Computer Products Inc." } , + { 0x10E7, "Vadem", "Vadem" } , + { 0x10E8, "AMCC", "Applied Micro Circuits Corp." } , + { 0x10E9, "Alps", "Alps Electronic Corp. Ltd." } , + { 0x10EA, "Tvia", "Tvia, Inc." } , + { 0x10EB, "Artist", "Artist Graphics" } , + { 0x10EC, "Realtek", "Realtek Semiconductor" } , + { 0x10ED, "Ascii", "Ascii Corporation" } , + { 0x10EE, "Xilinx", "Xilinx Corporation" } , + { 0x10EF, "Racore", "Racore Computer Products" } , + { 0x10F0, "Real-Time Graphics & Video", "Curtiss-Wright Controls Embedded Computing" } , + { 0x10F1, "Tyan", "Tyan Computer" } , + { 0x10F2, "Achme", "Achme Computer Inc. - GONE !!!!" } , + { 0x10F3, "Alaris", "Alaris Inc." } , + { 0x10F4, "S-Mos", "S-Mos Systems" } , + { 0x10F5, "NKK", "NKK Corporation" } , + { 0x10F6, "CES", "Creative Electronic Systems SA" } , + { 0x10F7, "Matsushita", "Matsushita Electric Industrial Corp." } , + { 0x10F8, "Altos", "Altos India Ltd." } , + { 0x10F9, "PC-Direct", "PC Direct" } , + { 0x10FA, "Truevision", "Truevision" } , + { 0x10FB, "Thesys", "Thesys Microelectronic's" } , + { 0x10FC, "I-O", "I-O Data Device Inc." } , + { 0x10FD, "Soyo", "Soyo Technology Corp. Ltd." } , + { 0x10FE, "Fast", "Fast Electronic GmbH" } , + { 0x10FF, "Ncube", "Ncube" } , + { 0x1100, "Jazz", "Jazz Multimedia" } , + { 0x1101, "Initio", "Initio Corporation" } , + { 0x1102, "Creative Labs", "Creative Technology LTD." } , + { 0x1103, "Highpoint", "Triones Technologies Inc. (HighPoint)" } , + { 0x1104, "Rasterops", "Rasterops" } , + { 0x1105, "Sigma", "Sigma Designs Inc." } , + { 0x1106, "VIA", "VIA Technology" } , + { 0x1107, "Stratus", "Stratus Computer" } , + { 0x1108, "Proteon", "Proteon Inc." } , + { 0x1109, "Cogent", "Adaptec/Cogent Data Technologies" } , + { 0x110A, "Siemens", "Siemens Nixdorf AG" } , + { 0x110B, "Chromatic", "Chromatic Research Inc" } , + { 0x110C, "Mini-Max", "Mini-Max Technology Inc." } , + { 0x110D, "ZNYX", "ZNYX Corporation" } , + { 0x110E, "CPU Tech.", "CPU Technology" } , + { 0x110F, "Ross", "Ross Technology" } , + { 0x1112, "Osicom", "Osicom Technologies Inc." } , + { 0x1113, "Accton", "Accton Technology Corporation" } , + { 0x1114, "Atmel", "Atmel Corp." } , + { 0x1116, "Data Translation", "Data Translation, Inc." } , + { 0x1117, "Datacube", "Datacube Inc." } , + { 0x1118, "Berg", "Berg Electronics" } , + { 0x1119, "Vortex", "ICP vortex Computersysteme GmbH" } , + { 0x111A, "Eff. Net.", "Efficent Networks" } , + { 0x111C, "Tricord", "Tricord Systems Inc." } , + { 0x111D, "IDT", "Integrated Device Technology Inc." } , + { 0x111F, "PDI", "Precision Digital Images" } , + { 0x1120, "EMC", "EMC Corp." } , + { 0x1121, "Zilog", "Zilog" } , + { 0x1123, "EDI", "Excellent Design Inc." } , + { 0x1124, "Leutron", "Leutron Vision AG" } , + { 0x1125, "Eurocore", "Eurocore/Vigra" } , + { 0x1127, "FORE RUNNER LE", "FORE Systems" } , + { 0x1129, "Firmworks", "Firmworks" } , + { 0x112A, "Hermes", "Hermes Electronics Co. Ltd." } , + { 0x112C, "Zenith", "Zenith Data Systems" } , + { 0x112D, "Ravicad", "Ravicad" } , + { 0x112E, "Infomedia", "Infomedia" } , + { 0x1130, "Computervision", "Computervision" } , + { 0x1131, "72c0ai913629", "Philips Semiconductors" } , + { 0x1132, "Mitel", "Mitel Corp." } , + { 0x1133, "EIC", "Eicon Networks Corporation" } , + { 0x1134, "MCS", "Mercury Computer Systems Inc." } , + { 0x1135, "Fuji", "Fuji Xerox Co Ltd" } , + { 0x1136, "Momentum", "Momentum Data Systems" } , + { 0x1137, "Cisco", "Cisco Systems Inc" } , + { 0x1138, "Ziatech", "Ziatech Corporation" } , + { 0x1139, "Dyn. Pict.", "Dynamic Pictures Inc" } , + { 0x113A, "FWB", "FWB Inc" } , + { 0x113B, "NCD", "Network Computing Devices" } , + { 0x113C, "Cyclone", "Cyclone Microsystems Inc." } , + { 0x113D, "Leading Edge", "Leading Edge Products Inc" } , + { 0x113E, "Sanyo", "Sanyo Electric Co" } , + { 0x113F, "Equinox", "Equinox Systems" } , + { 0x1140, "Intervoice", "Intervoice Inc" } , + { 0x1141, "Crest", "Crest Microsystem Inc" } , + { 0x1142, "Alliance", "Alliance Semiconductor" } , + { 0x1143, "Netpower", "Netpower Inc" } , + { 0x1144, "Cinn. Mil.", "Cincinnati Milacron" } , + { 0x1145, "Workbit", "Workbit Corp" } , + { 0x1146, "Force", "Force Computers" } , + { 0x1147, "Interface", "Interface Corp" } , + { 0x1148, "Marvell", "Marvell Semiconductor Germany GmbH" } , + { 0x1149, "Win System", "Win System Corporation" } , + { 0x114A, "VMIC", "VMIC" } , + { 0x114B, "Canopus", "Canopus corporation" } , + { 0x114C, "Annabooks", "Annabooks" } , + { 0x114D, "IC Corp.", "IC Corporation" } , + { 0x114E, "Nikon", "Nikon Systems Inc" } , + { 0x114F, "Digi", "Digi International" } , + { 0x1150, "TMC", "Thinking Machines Corporation" } , + { 0x1151, "JAE", "JAE Electronics Inc." } , + { 0x1153, "Land Win", "Land Win Electronic Corp" } , + { 0x1154, "Melco", "Melco Inc" } , + { 0x1155, "Pine", "Pine Technology Ltd" } , + { 0x1156, "Periscope", "Periscope Engineering" } , + { 0x1157, "Avsys", "Avsys Corporation" } , + { 0x1158, "Voarx", "Voarx R&D Inc" } , + { 0x1159, "Mutech", "Mutech" } , + { 0x115A, "Harlequin", "Harlequin Ltd" } , + { 0x115B, "Parallax", "Parallax Graphics" } , + { 0x115C, "Photron", "Photron Ltd." } , + { 0x115D, "Xircom", "Xircom" } , + { 0x115E, "Peer", "Peer Protocols Inc" } , + { 0x115F, "Maxtorr", "Maxtor Corporation" } , + { 0x1160, "Megasoft", "Megasoft Inc" } , + { 0x1161, "PFU", "PFU Ltd" } , + { 0x1162, "OA Lab", "OA Laboratory Co Ltd" } , + { 0x1163, "Rendition", "Rendition Inc" } , + { 0x1164, "APT", "Advanced Peripherals Tech" } , + { 0x1165, "Imagraph", "Imagraph Corporation" } , + { 0x1166, "BRCM/ServerWorks", "Broadcom / ServerWorks" } , + { 0x1167, "Mutoh", "Mutoh Industries Inc" } , + { 0x1168, "Thine", "Thine Electronics Inc" } , + { 0x1169, "CDAC", "Centre f/Dev. of Adv. Computing" } , + { 0x116A, "Luminex", "Luminex Software, Inc" } , + { 0x116B, "Connectware", "Connectware Inc" } , + { 0x116C, "Int Res.", "Intelligent Resources" } , + { 0x116E, "EFI", "Electronics for Imaging" } , + { 0x1170, "Inventec", "Inventec Corporation" } , + { 0x1172, "Altera", "Altera Corporation" } , + { 0x1173, "Adobe", "Adobe Systems" } , + { 0x1174, "Bridgeport", "Bridgeport Machines" } , + { 0x1175, "Mitron", "Mitron Computer Inc." } , + { 0x1176, "SBE", "SBE" } , + { 0x1177, "Silicon Eng.", "Silicon Engineering" } , + { 0x1178, "Alfa", "Alfa Inc" } , + { 0x1179, "Toshiba", "Toshiba America Info Systems" } , + { 0x117A, "A-Trend", "A-Trend Technology" } , + { 0x117B, "LG", "LG (Lucky Goldstar) Electronics Inc." } , + { 0x117C, "Atto", "Atto Technology" } , + { 0x117D, "B&D", "Becton & Dickinson" } , + { 0x117E, "T/R", "T/R Systems" } , + { 0x117F, "ICS", "Integrated Circuit Systems" } , + { 0x1180, "Ricoh", "Ricoh Company, Ltd." } , + { 0x1183, "Fujikura", "Fujikura Ltd" } , + { 0x1184, "Forks", "Forks Inc" } , + { 0x1185, "Dataworld", "Dataworld" } , + { 0x1186, "D-Link", "D-Link System Inc" } , + { 0x1187, "ATL", "Advanced Technology Laboratories" } , + { 0x1188, "Shima", "Shima Seiki Manufacturing Ltd." } , + { 0x1189, "Matsushita", "Matsushita Electronics" } , + { 0x118A, "Hilevel", "Hilevel Technology" } , + { 0x118B, "Hypertec", "Hypertec Pty Ltd" } , + { 0x118C, "Corollary", "Corollary Inc" } , + { 0x118D, "BitFlow", "BitFlow Inc" } , + { 0x118E, "Hermstedt", "Hermstedt AG" } , + { 0x118F, "Green", "Green Logic" } , + { 0x1190, "Tripace", "Tripace" } , + { 0x1191, "Acard", "Acard Technology Corp." } , + { 0x1192, "Densan", "Densan Co. Ltd" } , + { 0x1194, "Toucan", "Toucan Technology" } , + { 0x1195, "Ratoc", "Ratoc System Inc" } , + { 0x1196, "Hytec", "Hytec Electronics Ltd" } , + { 0x1197, "Gage", "Gage Applied Technologies" } , + { 0x1198, "Lambda", "Lambda Systems Inc" } , + { 0x1199, "Attachmate", "Attachmate Corp." } , + { 0x119A, "Mind Share", "Mind/Share Inc." } , + { 0x119B, "Omega", "Omega Micro Inc." } , + { 0x119C, "ITI", "Information Technology Inst." } , + { 0x119D, "Bug", "Bug Sapporo Japan" } , + { 0x119E, "Fujitsu", "Fujitsu Microelectronics Ltd." } , + { 0x119F, "Bull", "Bull Hn Information Systems" } , + { 0x11A1, "Hamamatsu", "Hamamatsu Photonics K.K." } , + { 0x11A2, "Sierra", "Sierra Research and Technology" } , + { 0x11A3, "Deuretzbacher", "Deuretzbacher GmbH & Co. Eng. KG" } , + { 0x11A4, "Barco", "Barco" } , + { 0x11A5, "MicroUnity", "MicroUnity Systems Engineering Inc." } , + { 0x11A6, "Pure Data", "Pure Data" } , + { 0x11A7, "Power Comp.", "Power Computing Corp." } , + { 0x11A8, "Systech", "Systech Corp." } , + { 0x11A9, "InnoSys", "InnoSys Inc." } , + { 0x11AA, "Actel", "Actel" } , + { 0x11AB, "Marvell", "Marvell Semiconductor" } , + { 0x11AC, "Canon", "Canon Information Systems" } , + { 0x11AD, "Lite-On", "Lite-On Technology Corp." } , + { 0x11AE, "Scitex", "Scitex Corporation Ltd" } , + { 0x11AF, "Avid", "Avid Technology, Inc." } , + { 0x11B0, "QuickLogic", "Quicklogic Corp" } , + { 0x11B1, "Apricot", "Apricot Computers" } , + { 0x11B2, "Kodak", "Eastman Kodak" } , + { 0x11B3, "Barr", "Barr Systems Inc." } , + { 0x11B4, "Leitch", "Leitch Technology International" } , + { 0x11B5, "Radstone", "Radstone Technology Ltd." } , + { 0x11B6, "United Video", "United Video Corp" } , + { 0x11B7, "Motorola", "Motorola" } , + { 0x11B8, "Xpoint", "Xpoint Technologies Inc" } , + { 0x11B9, "Pathlight", "Pathlight Technology Inc." } , + { 0x11BA, "Videotron", "Videotron Corp" } , + { 0x11BB, "Pyramid", "Pyramid Technology" } , + { 0x11BC, "Net. Periph.", "Network Peripherals Inc" } , + { 0x11BD, "NABOHO", "lota" } , + { 0x11BE, "IMI", "International Microcircuits Inc" } , + { 0x11BF, "Astrodesign", "Astrodesign Inc." } , + { 0x11C1, "Agere", "Erick Medina" } , + { 0x11C2, "Sand", "Sand Microelectronics" } , + { 0x11C4, "Doc. Tech.", "Document Technologies Ind." } , + { 0x11C5, "Shiva", "Shiva Corporatin" } , + { 0x11C6, "Dainippon", "Dainippon Screen Mfg. Co" } , + { 0x11C7, "D.C.M.", "D.C.M. Data Systems" } , + { 0x11C8, "Dolphin", "Dolphin Interconnect Solutions" } , + { 0x11C9, "MAGMA", "MAGMA" } , + { 0x11CA, "LSI Sys.", "LSI Systems Inc" } , + { 0x11CB, "Specialix", "Specialix International Ltd." } , + { 0x11CC, "M&K", "Michels & Kleberhoff Computer GmbH" } , + { 0x11CD, "HAL", "HAL Computer Systems Inc." } , + { 0x11CE, "PRI", "Primary Rate Inc" } , + { 0x11CF, "PEC", "Pioneer Electronic Corporation" } , + { 0x11D0, "BAE", "BAE SYSTEMS - Manassas" } , + { 0x11D1, "AuraVision", "AuraVision Corporation" } , + { 0x11D2, "Intercom", "Intercom Inc." } , + { 0x11D3, "Trancell", "Trancell Systems Inc" } , + { 0x11D4, "ADI", "Analog Devices, Inc." } , + { 0x11D5, "Tahoma", "Tahoma Technology" } , + { 0x11D6, "Tekelec", "Tekelec Technologies" } , + { 0x11D7, "Trenton", "TRENTON Technology, Inc." } , + { 0x11D8, "ITD", "Image Technologies Development" } , + { 0x11D9, "Tec", "Tec Corporation" } , + { 0x11DA, "Novell", "Novell" } , + { 0x11DB, "Sega", "Sega Enterprises Ltd" } , + { 0x11DC, "Questra", "Questra Corp" } , + { 0x11DD, "Crosfield", "Crosfield Electronics Ltd" } , + { 0x11DE, "Zoran", "Zoran Corporation" } , + { 0x11E1, "Gec Plessey", "Gec Plessey Semi Inc" } , + { 0x11E2, "Samsung", "Samsung Information Systems America" } , + { 0x11E3, "QuickLogic", "Quicklogic Corp" } , + { 0x11E4, "Second Wave", "Second Wave Inc" } , + { 0x11E5, "IIX", "IIX Consulting" } , + { 0x11E6, "Mitsui", "Mitsui-Zosen System Research" } , + { 0x11E8, "DPSI", "Digital Processing Systems Inc" } , + { 0x11E9, "Highwater", "Highwater Designs Ltd" } , + { 0x11EA, "Elsag", "Elsag Bailey" } , + { 0x11EB, "Formation", "Formation, Inc" } , + { 0x11EC, "Coreco", "Coreco Inc" } , + { 0x11ED, "Mediamatics", "Mediamatics" } , + { 0x11EE, "Dome", "Dome Imaging Systems Inc" } , + { 0x11EF, "Nicolet", "Nicolet Technologies BV" } , + { 0x11F0, "Compu-Shack", "Compu-Shack GmbH" } , + { 0x11F2, "Pic-Tel", "Picture Tel Japan KK" } , + { 0x11F3, "Keithley", "Keithley Metrabyte" } , + { 0x11F4, "Kinetic", "Kinetic Systems Corporation" } , + { 0x11F5, "Comp Dev", "Computing Devices Intl" } , + { 0x11F6, "Powermatic", "Powermatic Data Systems Ltd" } , + { 0x11F7, "S-A", "Scientific Atlanta" } , + { 0x11F8, "PMC-Sierra", "PMC-Sierra Inc." } , + { 0x11F9, "I-Cube", "I-Cube Inc" } , + { 0x11FA, "Kasan", "Kasan Electronics Co Ltd" } , + { 0x11FB, "Datel", "Datel Inc" } , + { 0x11FD, "High Street", "High Street Consultants" } , + { 0x11FE, "Comtrol", "Comtrol Corp" } , + { 0x11FF, "Scion", "Scion Corp" } , + { 0x1200, "CSS", "CSS Corp" } , + { 0x1201, "Vista", "Vista Controls Corp" } , + { 0x1202, "Network Gen", "Network General Corp" } , + { 0x1203, "Agfa", "Bayer Corporation Agfa Div" } , + { 0x1204, "Lattice", "Lattice Semiconductor Corp" } , + { 0x1205, "Array", "Array Corp" } , + { 0x1206, "Amdahl", "Amdahl Corp" } , + { 0x1208, "Parsytec", "Parsytec GmbH" } , + { 0x1209, "Sci Sys", "Sci Systems Inc" } , + { 0x120A, "Synaptel", "Synaptel" } , + { 0x120B, "Adaptive", "Adaptive Solutions" } , + { 0x120D, "Comp Labs", "Compression Labs Inc." } , + { 0x120E, "Cyclades", "Cyclades Corporation" } , + { 0x120F, "Essential", "Essential Communications" } , + { 0x1210, "Hyperparallel", "Hyperparallel Technologies" } , + { 0x1211, "Braintech", "Braintech Inc" } , + { 0x1213, "AISI", "Applied Intelligent Systems Inc" } , + { 0x1214, "Perf Tech", "Performance Technologies Inc" } , + { 0x1215, "Interware", "Interware Co Ltd" } , + { 0x1216, "Purup Eskofot", "Purup-Eskofot A/S" } , + { 0x1217, "O2Micro", "O2Micro Inc" } , + { 0x1218, "Hybricon", "Hybricon Corp" } , + { 0x1219, "First Virtual", "First Virtual Corp" } , + { 0x121A, "3dfx", "3dfx Interactive Inc" } , + { 0x121B, "ATM", "Advanced Telecommunications Modules" } , + { 0x121C, "Nippon Texa", "Nippon Texa Co Ltd" } , + { 0x121D, "Lippert", "Lippert Automationstechnik GmbH" } , + { 0x121E, "CSPI", "CSPI" } , + { 0x121F, "Arcus", "Arcus Technology Inc" } , + { 0x1220, "Ariel", "Ariel Corporation" } , + { 0x1221, "Contec", "Contec Microelectronics Europe BV" } , + { 0x1222, "Ancor", "Ancor Communications Inc" } , + { 0x1223, "Emerson Network Power", "Emerson Network Power, Embedded Computing" } , + { 0x1224, "Int. Img.", "Interactive Images" } , + { 0x1225, "Power IO", "Power I/O Inc." } , + { 0x1227, "Tech-Source", "Tech-Source" } , + { 0x1228, "Norsk", "Norsk Elektro Optikk A/S" } , + { 0x1229, "Data Kin", "Data Kinesis Inc." } , + { 0x122A, "Int. Telecom", "Integrated Telecom" } , + { 0x122B, "LG Ind.", "LG Industrial Systems Co. Ltd." } , + { 0x122C, "sci-worx", "sci-worx GmbH" } , + { 0x122D, "Aztech", "Aztech System Ltd" } , + { 0x122E, "Xyratex", "Xyratex" } , + { 0x122F, "Andrew", "Andrew Corp." } , + { 0x1230, "Fishcamp", "Fishcamp Engineering" } , + { 0x1231, "WMI", "Woodward McCoach Inc." } , + { 0x1233, "Bus-Tech", "Bus-Tech Inc." } , + { 0x1234, "Bochs", "Bochs" } , + { 0x1236, "Sigma Designs", "Sigma Designs, Inc" } , + { 0x1237, "Alta Tech", "Alta Technology Corp." } , + { 0x1238, "Adtran", "Adtran" } , + { 0x1239, "3DO", "The 3DO Company" } , + { 0x123A, "Visicom", "Visicom Laboratories Inc." } , + { 0x123B, "Seeq", "Seeq Technology Inc." } , + { 0x123C, "Century Sys", "Century Systems Inc." } , + { 0x123D, "EDT", "Engineering Design Team Inc." } , + { 0x123F, "C-Cube", "C-Cube Microsystems" } , + { 0x1240, "Marathon", "Marathon Technologies Corp." } , + { 0x1241, "DSC", "DSC Communications" } , + { 0x1242, "JNI", "JNI Corporation" } , + { 0x1243, "Delphax", "Delphax" } , + { 0x1244, "AVM", "AVM AUDIOVISUELLES MKTG & Computer GmbH" } , + { 0x1245, "APD", "APD S.A." } , + { 0x1246, "Dipix", "Dipix Technologies Inc" } , + { 0x1247, "Xylon", "Xylon Research Inc." } , + { 0x1248, "Central Data", "Central Data Corp." } , + { 0x1249, "Samsung", "Samsung Electronics Co. Ltd." } , + { 0x124A, "AEG", "AEG Electrocom GmbH" } , + { 0x124C, "Solitron", "Solitron Technologies Inc." } , + { 0x124D, "Stallion", "Stallion Technologies" } , + { 0x124E, "Cylink", "Cylink" } , + { 0x124F, "Infortrend", "Infortrend Technology Inc" } , + { 0x1250, "Hitachi", "Hitachi Microcomputer System Ltd." } , + { 0x1251, "VLSI Sol.", "VLSI Solution OY" } , + { 0x1253, "Guzik", "Guzik Technical Enterprises" } , + { 0x1254, "Linear Systems", "Linear Systems Ltd." } , + { 0x1255, "Optibase", "Optibase Ltd." } , + { 0x1256, "Perceptive", "Perceptive Solutions Inc." } , + { 0x1257, "Vertex", "Vertex Networks Inc." } , + { 0x1258, "Gilbarco", "Gilbarco Inc." } , + { 0x1259, "Allied Tsyn", "Allied Telesyn International" } , + { 0x125A, "ABB Pwr", "ABB Power Systems" } , + { 0x125B, "Asix", "Asix Electronics Corp." } , + { 0x125C, "Aurora", "Aurora Technologies Inc." } , + { 0x125D, "ESS", "ESS Technology" } , + { 0x125E, "Specvideo", "Specialvideo Engineering SRL" } , + { 0x125F, "Concurrent", "Concurrent Technologies Inc." } , + { 0x1260, "Intersil", "Intersil Corporation" } , + { 0x1261, "Matsushita", "Matsushita-Kotobuki Electronics Indu" } , + { 0x1262, "ES Comp.", "ES Computer Co. Ltd." } , + { 0x1263, "Sonic Sol.", "Sonic Solutions" } , + { 0x1264, "Aval Nag.", "Aval Nagasaki Corp." } , + { 0x1265, "Casio", "Casio Computer Co. Ltd." } , + { 0x1266, "Microdyne", "Microdyne Corp." } , + { 0x1267, "SA Telecom", "S.A. Telecommunications" } , + { 0x1268, "Tektronix", "Tektronix" } , + { 0x1269, "SGS Thomson", "Thomson-CSF/TTM" } , + { 0x126A, "Lexmark", "Lexmark International Inc." } , + { 0x126B, "Adax", "Adax Inc." } , + { 0x126C, "Nortel", "Nortel Networks Corp." } , + { 0x126D, "Splash", "Splash Technology Inc." } , + { 0x126E, "Sumitomo", "Sumitomo Metal Industries Ltd." } , + { 0x126F, "Sil Motion", "Silicon Motion" } , + { 0x1270, "Olympus", "Olympus Optical Co. Ltd." } , + { 0x1271, "GW Instr.", "GW Instruments" } , + { 0x1272, "Telematics", "Telematics International" } , + { 0x1273, "Hughes", "Hughes Network Systems" } , + { 0x1274, "Ensoniq", "Ensoniq" } , + { 0x1275, "NetApp", "Network Appliance" } , + { 0x1276, "Sw Net Tech", "Switched Network Technologies Inc." } , + { 0x1277, "Comstream", "Comstream" } , + { 0x1278, "Transtech", "Transtech Parallel Systems" } , + { 0x1279, "Transmeta", "Transmeta Corp." } , + { 0x127B, "Pixera", "Pixera Corp" } , + { 0x127C, "Crosspoint", "Crosspoint Solutions Inc." } , + { 0x127D, "Vela", "Vela Research LP" } , + { 0x127E, "Winnow", "Winnov L.P." } , + { 0x127F, "Fujifilm", "Fujifilm" } , + { 0x1280, "Photoscript", "Photoscript Group Ltd." } , + { 0x1281, "Yokogawa", "Yokogawa Electronic Corp." } , + { 0x1282, "Davicom", "Davicom Semiconductor Inc." } , + { 0x1283, " Zamora", "Waldo" } , + { 0x1285, "Plat Tech", "Platform Technologies Inc." } , + { 0x1286, "MAZeT", "MAZeT GmbH" } , + { 0x1287, "LuxSonor", "LuxSonor Inc." } , + { 0x1288, "Timestep", "Timestep Corp." } , + { 0x1289, "AVC Tech", "AVC Technology Inc." } , + { 0x128A, "Asante", "Asante Technologies Inc." } , + { 0x128B, "Transwitch", "Transwitch Corp." } , + { 0x128C, "Retix", "Retix Corp." } , + { 0x128D, "G2 Net", "G2 Networks Inc." } , + { 0x128F, "Tateno", "Tateno Dennou Inc." } , + { 0x1290, "Sord", "Sord Computer Corp." } , + { 0x1291, "NCS Comp", "NCS Computer Italia" } , + { 0x1292, "Tritech", "Tritech Microelectronics Intl PTE" } , + { 0x1293, "M Reality", "Media Reality Technology" } , + { 0x1294, "Rhetorex", "Rhetorex Inc." } , + { 0x1295, "Imagenation", "Imagenation Corp." } , + { 0x1296, "Kofax", "Kofax Image Products" } , + { 0x1297, "Shuttle Computer", "Shuttle Computer" } , + { 0x1298, "Spellcaster", "Spellcaster Telecommunications Inc." } , + { 0x1299, "Know Tech", "Knowledge Technology Laboratories" } , + { 0x129A, "VMETRO", "VMETRO Inc." } , + { 0x129B, "Img Access", "Image Access" } , + { 0x129D, "CompCore", "CompCore Multimedia Inc." } , + { 0x129E, "Victor Jpn", "Victor Co. of Japan Ltd." } , + { 0x129F, "OEC Med", "OEC Medical Systems Inc." } , + { 0x12A0, "A-B", "Allen Bradley Co." } , + { 0x12A1, "Simpact", "Simpact Inc" } , + { 0x12A2, "NewGen", "NewGen Systems Corp." } , + { 0x12A3, "Lucent", "Lucent Technologies AMR" } , + { 0x12A4, "NTT Elect", "NTT Electronics Technology Co." } , + { 0x12A5, "Vision Dyn", "Vision Dynamics Ltd." } , + { 0x12A6, "Scalable", "Scalable Networks Inc." } , + { 0x12A7, "AMO", "AMO GmbH" } , + { 0x12A8, "News Datacom", "News Datacom" } , + { 0x12A9, "Xiotech", "Xiotech Corp." } , + { 0x12AA, "SDL", "SDL Communications Inc." } , + { 0x12AB, "Yuan Yuan", "Yuan Yuan Enterprise Co. Ltd." } , + { 0x12AC, "MeasureX", "MeasureX Corp." } , + { 0x12AD, "MULTIDATA", "MULTIDATA GmbH" } , + { 0x12AE, "Alteon", "Alteon Networks Inc." } , + { 0x12AF, "TDK USA", "TDK USA Corp." } , + { 0x12B0, "Jorge Sci", "Jorge Scientific Corp." } , + { 0x12B1, "GammaLink", "GammaLink" } , + { 0x12B2, "Gen Signal", "General Signal Networks" } , + { 0x12B3, "Inter-Face", "Inter-Face Co. Ltd." } , + { 0x12B4, "Future Tel", "Future Tel Inc." } , + { 0x12B5, "Granite", "Granite Systems Inc." } , + { 0x12B7, "Acumen", "Acumen" } , + { 0x12B8, "Korg", "Korg" } , + { 0x12B9, "3Com", "3Com Corporation" } , + { 0x12BA, "Bittware", "Bittware, Inc" } , + { 0x12BB, "Nippon Uni", "Nippon Unisoft Corp." } , + { 0x12BC, "Array Micro", "Array Microsystems" } , + { 0x12BD, "Computerm", "Computerm Corp." } , + { 0x12BF, "Fujifilm", "Fujifilm Microdevices" } , + { 0x12C0, "Infimed", "Infimed" } , + { 0x12C1, "GMM Res", "GMM Research Corp." } , + { 0x12C2, "Mentec", "Mentec Ltd." } , + { 0x12C3, "Holtek", "Holtek Microelectronics Inc." } , + { 0x12C4, "Connect Tech", "Connect Tech Inc." } , + { 0x12C5, "PicturEl", "Picture Elements Inc." } , + { 0x12C6, "Mitani", "Mitani Corp." } , + { 0x12C7, "Dialogic", "Dialogic Corp." } , + { 0x12C8, "G Force", "G Force Co. Ltd." } , + { 0x12C9, "Gigi Ops", "Gigi Operations" } , + { 0x12CA, "ICE", "Integrated Computing Engines, Inc." } , + { 0x12CB, "Antex", "Antex Electronics Corp." } , + { 0x12CC, "Pluto", "Pluto Technologies International" } , + { 0x12CD, "Aims Lab", "Aims Lab" } , + { 0x12CE, "Netspeed", "Netspeed Inc." } , + { 0x12CF, "Prophet", "Prophet Systems Inc." } , + { 0x12D0, "GDE Sys", "GDE Systems Inc." } , + { 0x12D1, "PsiTech", "PsiTech" } , + { 0x12D3, "Vingmed", "Vingmed Sound A/S" } , + { 0x12D4, "Ulticom", "Ulticom, Inc." } , + { 0x12D5, "Equator", "Equator Technologies" } , + { 0x12D6, "Analogic", "Analogic Corp." } , + { 0x12D7, "Biotronic", "Biotronic SRL" } , + { 0x12D8, "Pericom", "Pericom Semiconductor" } , + { 0x12D9, "Aculab", "Aculab Plc." } , + { 0x12DA, "TrueTime", "TrueTime" } , + { 0x12DB, "Annapolis", "Annapolis Micro Systems Inc." } , + { 0x12DC, "Symicron", "Symicron Computer Communication Ltd." } , + { 0x12DD, "MGI", "Management Graphics Inc." } , + { 0x12DE, "Rainbow", "Rainbow Technologies" } , + { 0x12DF, "SBS Tech", "SBS Technologies Inc." } , + { 0x12E0, "Chase", "Chase Research PLC" } , + { 0x12E1, "Nintendo", "Nintendo Co. Ltd." } , + { 0x12E2, "Datum", "Datum Inc. Bancomm-Timing Division" } , + { 0x12E3, "Imation", "Imation Corp. - Medical Imaging Syst" } , + { 0x12E4, "Brooktrout", "Brooktrout Technology Inc." } , + { 0x12E6, "Cirel", "Cirel Systems" } , + { 0x12E7, "Sebring", "Sebring Systems Inc" } , + { 0x12E8, "CRISC", "CRISC Corp." } , + { 0x12E9, "GE Spacenet", "GE Spacenet" } , + { 0x12EB, "Aureal", "Aureal Semiconductor" } , + { 0x12EC, "3A Intl", "3A International Inc." } , + { 0x12ED, "Optivision", "Optivision Inc." } , + { 0x12EE, "Orange Micro", "Orange Micro, Inc." } , + { 0x12EF, "Vienna", "Vienna Systems" } , + { 0x12F0, "Pentek", "Pentek" } , + { 0x12F1, "Sorenson", "Sorenson Vision Inc." } , + { 0x12F2, "Gammagraphx", "Gammagraphx Inc." } , + { 0x12F4, "Megatel", "Megatel" } , + { 0x12F5, "Forks", "Forks" } , + { 0x12F7, "Cognex", "Cognex" } , + { 0x12F8, "Electronic-Design", "Electronic-Design GmbH" } , + { 0x12F9, "FFT", "FourFold Technologies" } , + { 0x12FB, "SSP", "Spectrum Signal Processing" } , + { 0x12FC, "CEC", "Capital Equipment Corp" } , + { 0x12FE, "esd", "esd Electronic System Design GmbH" } , + { 0x1303, "II", "Innovative Integration" } , + { 0x1304, "", "Juniper Networks Inc." } , + { 0x1307, "ComputerBoards", "ComputerBoards" } , + { 0x1308, "Jato", "Jato Technologies Inc." } , + { 0x130A, "Mitsubishi", "Mitsubishi Electric Microcomputer" } , + { 0x130B, "Colorgraphic", "Colorgraphic Communications Corp" } , + { 0x130F, "", "Advanet Inc." } , + { 0x1310, "", "Gespac" } , + { 0x1312, "Microscan", "Microscan Systems Inc" } , + { 0x1313, "", "Yaskawa Electric Co." } , + { 0x1316, "", "Teradyne Inc." } , + { 0x1317, "ADMtek", "ADMtek Inc" } , + { 0x1318, "Packet Engines", "Packet Engines, Inc." } , + { 0x1319, "Forte Media2", "Forte Media" } , + { 0x131F, "", "SIIG" } , + { 0x1325, "", "Salix Technologies Inc" } , + { 0x1326, "", "Seachange International" } , + { 0x1328, "CIFELLI", "CIFELLI SYSTEMS CORPORATION" } , + { 0x1331, "RadiSys", "RadiSys Corporation" } , + { 0x1332, "VMetro", "VMetro" } , + { 0x1335, "Videomail", "Videomail Inc." } , + { 0x133D, "", "Prisa Networks" } , + { 0x133F, "", "SCM Microsystems" } , + { 0x1342, "", "Promax Systems Inc" } , + { 0x1344, "Micron", "Micron Technology, Inc." } , + { 0x1347, "Spectracom", "Spectracom Corporation" } , + { 0x134A, "DTC", "DTC Technology Corp." } , + { 0x134B, "", "ARK Research Corp." } , + { 0x134C, "", "Chori Joho System Co. Ltd" } , + { 0x134D, "PCTEL", "PCTEL Inc." } , + { 0x135A, "", "Brain Boxes Limited" } , + { 0x135B, "", "Giganet Inc." } , + { 0x135C, "", "Quatech Inc" } , + { 0x135D, "ABB Network Partn", "ABB Network Partner AB" } , + { 0x135E, "Sealevel", "Sealevel Systems Inc." } , + { 0x135F, "", "I-Data International A-S" } , + { 0x1360, "Meinberg Funkuhren", "Meinberg Funkuhren GmbH & Co. KG" } , + { 0x1361, "", "Soliton Systems K.K." } , + { 0x1363, "", "Phoenix Technologies Ltd" } , + { 0x1365, "Hypercope", "Hypercope Corp." } , + { 0x1366, "Teijin", "Teijin Seiki Co. Ltd." } , + { 0x1367, "", "Hitachi Zosen Corporation" } , + { 0x1368, "", "Skyware Corporation" } , + { 0x1369, "Digigram", "Digigram" } , + { 0x136B, "", "Kawasaki Steel Corporation" } , + { 0x136C, "", "Adtek System Science Co Ltd" } , + { 0x1375, "", "Boeing - Sunnyvale" } , + { 0x137A, "MOTU", "Mark Of The Unicorn Inc" } , + { 0x137B, "", "PPT Vision" } , + { 0x137C, "", "Iwatsu Electric Co Ltd" } , + { 0x137D, "", "Dynachip Corporation" } , + { 0x137E, "PTSC", "Patriot Scientific Corp." } , + { 0x1380, "SANRITZ", "Sanritz Automation Co LTC" } , + { 0x1381, "", "Brains Co. Ltd" } , + { 0x1382, "Marian", "Marian - Electronic & Software" } , + { 0x1384, "", "Stellar Semiconductor Inc" } , + { 0x1385, "Netgear", "Netgear" } , + { 0x1387, "Digital Signal Processing", "Curtiss-Wright Controls Embedded Computing" } , + { 0x1388, "", "Hitachi Information Technology Co Ltd" } , + { 0x1389, "Applicom", "Applicom International" } , + { 0x138B, "", "Tokimec Inc" } , + { 0x138E, "", "Basler GMBH" } , + { 0x138F, "", "Patapsco Designs Inc" } , + { 0x1390, "CDI", "Concept Development Inc." } , + { 0x1393, "", "Moxa Technologies Co Ltd" } , + { 0x1394, "Level One", "Level One Communications" } , + { 0x1395, "", "Ambicom Inc" } , + { 0x1396, "", "Cipher Systems Inc" } , + { 0x1397, "Cologne", "Cologne Chip Designs GmbH" } , + { 0x1398, "", "Clarion Co. Ltd" } , + { 0x139A, "", "Alacritech Inc" } , + { 0x139D, "", "Xstreams PLC/ EPL Limited" } , + { 0x139E, "", "Echostar Data Networks" } , + { 0x13A0, "", "Crystal Group Inc" } , + { 0x13A1, "", "Kawasaki Heavy Industries Ltd" } , + { 0x13A3, "HI-FN", "HI-FN Inc." } , + { 0x13A4, "", "Rascom Inc" } , + { 0x13A7, "", "amc330" } , + { 0x13A8, "XR", "Exar Corp." } , + { 0x13A9, "", "Siemens Medical Solutions" } , + { 0x13AA, "", "Nortel Networks - BWA Division" } , + { 0x13AF, "", "T.Sqware" } , + { 0x13B1, "", "Tamura Corporation" } , + { 0x13B4, "", "Wellbean Co Inc" } , + { 0x13B5, "", "ARM Ltd" } , + { 0x13B6, "pci\ven_13b6", "DLoG GMBH" } , + { 0x13B8, "", "Nokia Telecommunications OY" } , + { 0x13BD, "SHARP", "Sharp Corporation" } , + { 0x13BF, "", "Sharewave Inc" } , + { 0x13C0, "Microgate", "Microgate Corp." } , + { 0x13C1, "3ware", "3ware Inc." } , + { 0x13C2, "", "Technotrend Systemtechnik GMBH" } , + { 0x13C3, "", "Janz Computer AG" } , + { 0x13C7, "", "Blue Chip Technology Ltd" } , + { 0x13CC, "", "Metheus Corporation" } , + { 0x13CF, "", "Studio Audio & Video Ltd" } , + { 0x13D0, "A", "B2C2 Inc" } , + { 0x13D1, "AboCom", "AboCom Systems, Inc" } , + { 0x13D4, "", "Graphics Microsystems Inc" } , + { 0x13D6, "", "K.I. Technology Co Ltd" } , + { 0x13D7, "tos6205", "Toshiba Engineering Corporation" } , + { 0x13D8, "", "Phobos Corporation" } , + { 0x13D9, "", "Apex Inc" } , + { 0x13DC, "", "Netboost Corporation" } , + { 0x13DE, "", "ABB Robotics Products AB" } , + { 0x13DF, "E-Tech", "E-Tech Inc." } , + { 0x13E0, "GVC", "GVC Corporation" } , + { 0x13E3, "", "Nest Inc" } , + { 0x13E4, "", "Calculex Inc" } , + { 0x13E5, "", "Telesoft Design Ltd" } , + { 0x13E9, "", "Intraserver Technology Inc" } , + { 0x13EA, "", "Dallas Semiconductor" } , + { 0x13F0, "", "IC Plus Corporation" } , + { 0x13F1, "", "OCE - Industries S.A." } , + { 0x13F4, "", "Troika Networks Inc" } , + { 0x13F6, "C-Media", "C-Media Electronics Inc." } , + { 0x13F9, "", "NTT Advanced Technology Corp." } , + { 0x13FA, "Pentland", "Pentland Systems Ltd." } , + { 0x13FB, "", "Aydin Corp" } , + { 0x13FD, "", "Micro Science Inc" } , + { 0x13FE, "Advantech", "Advantech Co., Ltd." } , + { 0x13FF, "", "Silicon Spice Inc." } , + { 0x1400, "ArtX", "ArtX Inc" } , + { 0x1402, "Meilhaus Electronic", "Meilhaus Electronic GmbH Germany" } , + { 0x1404, "", "Fundamental Software Inc" } , + { 0x1406, "Oc", "Oce Print Logics Technologies S.A." } , + { 0x1407, "LAVA", "Lava Computer MFG Inc." } , + { 0x1408, "", "Aloka Co. Ltd" } , + { 0x1409, "SUNIX", "SUNIX Co., Ltd." } , + { 0x140A, "", "DSP Research Inc" } , + { 0x140B, "", "Ramix Inc" } , + { 0x140D, "", "Matsushita Electric Works Ltd" } , + { 0x140F, "", "Salient Systems Corp" } , + { 0x1412, "IC Ensemble", "IC Ensemble, Inc." } , + { 0x1413, "", "Addonics" } , + { 0x1415, "Oxford", "Oxford Semiconductor Ltd" } , + { 0x1418, "", "Kyushu Electronics Systems Inc" } , + { 0x1419, "", "Excel Switching Corp" } , + { 0x141B, "Gerd Mokwinski", "Zoom Telephonics Inc" } , + { 0x141E, "", "Fanuc Co. Ltd" } , + { 0x141F, "", "Visiontech Ltd" } , + { 0x1420, "", "Psion Dacom PLC" } , + { 0x1425, "", "ASIC Designers Inc" } , + { 0x1428, "", "Edec Co Ltd" } , + { 0x1429, "", "Unex Technology Corp." } , + { 0x142A, "", "Kingmax Technology Inc" } , + { 0x142B, "", "Radiolan" } , + { 0x142C, "", "Minton Optic Industry Co Ltd" } , + { 0x142D, "", "Pixstream Inc" } , + { 0x1430, "", "ITT Aerospace/Communications Division" } , + { 0x1433, "", "Eltec Elektronik AG" } , + { 0x1435, "RTD", "RTD Embedded Technologies, Inc." } , + { 0x1436, "", "CIS Technology Inc" } , + { 0x1437, "", "Nissin Inc Co" } , + { 0x1438, "", "Atmel-Dream" } , + { 0x143F, "", "Lightwell Co Ltd - Zax Division" } , + { 0x1441, "", "Agie SA." } , + { 0x1443, "Unibrain", "Unibrain S.A." } , + { 0x1445, "", "Logical Co Ltd" } , + { 0x1446, "", "Graphin Co. Ltd" } , + { 0x1447, "", "Aim GMBH" } , + { 0x1448, "Alesis", "Alesis Studio" } , + { 0x144A, "ADLINK", "ADLINK Technology Inc" } , + { 0x144B, "Loronix", "Loronix Information Systems, Inc." } , + { 0x144D, "", "sanyo" } , + { 0x1450, "", "Octave Communications Ind." } , + { 0x1451, "", "SP3D Chip Design GMBH" } , + { 0x1453, "", "Mycom Inc" } , + { 0x1458, "Giga-Byte", "Giga-Byte Technologies" } , + { 0x145C, "", "Cryptek" } , + { 0x145F, "Baldor", "Baldor Electric Company" } , + { 0x1460, "", "Dynarc Inc" } , + { 0x1462, "MSI", "Micro-Star International Co Ltd" } , + { 0x1463, "", "Fast Corporation" } , + { 0x1464, "ICS", "Interactive Circuits & Systems Ltd" } , + { 0x1468, "", "Ambit Microsystems Corp." } , + { 0x1469, "", "Cleveland Motion Controls" } , + { 0x146C, "", "Ruby Tech Corp." } , + { 0x146D, "", "Tachyon Inc." } , + { 0x146E, "", "WMS Gaming" } , + { 0x1471, "", "Integrated Telecom Express Inc" } , + { 0x1473, "", "Zapex Technologies Inc" } , + { 0x1474, "", "Doug Carson & Associates" } , + { 0x1477, "", "Net Insight" } , + { 0x1478, "", "Diatrend Corporation" } , + { 0x147B, "", "Abit Computer Corp." } , + { 0x147F, "", "Nihon Unisys Ltd." } , + { 0x1482, "", "Isytec - Integrierte Systemtechnik Gmbh" } , + { 0x1483, "", "Labway Coporation" } , + { 0x1485, "", "Erma - Electronic GMBH" } , + { 0x1489, "", "KYE Systems Corporation" } , + { 0x148A, "", "Opto 22" } , + { 0x148B, "", "Innomedialogic Inc." } , + { 0x148C, "CP (PowerColor)", "C.P. Technology Co. Ltd" } , + { 0x148D, "Digicom", "Digicom Systems Inc." } , + { 0x148E, "", "OSI Plus Corporation" } , + { 0x148F, "", "Plant Equipment Inc." } , + { 0x1490, "", "TC Labs Pty Ltd." } , + { 0x1493, "", "Maker Communications" } , + { 0x1495, "", "Tokai Communications Industry Co. Ltd" } , + { 0x1496, "", "Joytech Computer Co. Ltd." } , + { 0x1497, "SMA", "SMA Technologie AG" } , + { 0x1498, "Tews", "Tews Technologies" } , + { 0x1499, "", "Micro-Technology Co Ltd" } , + { 0x149A, "Andor Tech", "Andor Technology Ltd" } , + { 0x149B, "", "Seiko Instruments Inc" } , + { 0x149E, "", "Mapletree Networks Inc." } , + { 0x149F, "", "Lectron Co Ltd" } , + { 0x14A0, "", "Softing GMBH" } , + { 0x14A2, "", "Millennium Engineering Inc" } , + { 0x14A4, "sebastien", "GVC/BCM Advanced Research" } , + { 0x14A9, "Hivertec Inc.", "Hivertec Inc." } , + { 0x14AB, "", "Mentor Graphics Corp." } , + { 0x14B1, "", "Nextcom K.K." } , + { 0x14B3, "Xpeed", "Xpeed Inc." } , + { 0x14B4, "", "Philips Business Electronics B.V." } , + { 0x14B5, "Creamware", "Creamware GmbH" } , + { 0x14B6, "", "Quantum Data Corp." } , + { 0x14B7, "Proxim", "Proxim Inc." } , + { 0x14B9, "Aironet", "Aironet Wireless Communication" } , + { 0x14BA, "", "Internix Inc." } , + { 0x14BB, "", "Semtech Corporation" } , + { 0x14BE, "", "L3 Communications" } , + { 0x14C0, "Compal", "Compal Electronics, Inc." } , + { 0x14C1, "", "Myricom Inc." } , + { 0x14C2, "", "DTK Computer" } , + { 0x14C4, "", "Iwasaki Information Systems Co Ltd" } , + { 0x14C5, "", "ABB Automation Products AB" } , + { 0x14C6, "", "Data Race Inc" } , + { 0x14C7, "Modtech", "Modular Technology Ltd." } , + { 0x14C8, "Turbocomm", "Turbocomm Tech Inc" } , + { 0x14C9, "", "Odin Telesystems Inc" } , + { 0x14CB, "", "Billionton Systems Inc./Cadmus Micro Inc" } , + { 0x14CD, "", "Universal Scientific Ind." } , + { 0x14CF, "Tekmicro", "TEK Microsystems Inc." } , + { 0x14D4, "PANACOM", "Panacom Technology Corporation" } , + { 0x14D5, "", "Nitsuko Corporation" } , + { 0x14D6, "", "Accusys Inc" } , + { 0x14D7, "", "Hirakawa Hewtech Corp" } , + { 0x14D8, "", "Hopf Elektronik GMBH" } , + { 0x14D9, "", "Alpha Processor Inc" } , + { 0x14DB, "Avlab", "Avlab Technology Inc." } , + { 0x14DC, "Amplicon", "Amplicon Liveline Limited" } , + { 0x14DD, "", "Imodl Inc." } , + { 0x14DE, "", "Applied Integration Corporation" } , + { 0x14E3, "", "Amtelco" } , + { 0x14E4, "Broadcom", "Broadcom Corporation" } , + { 0x14EA, "Planex", "Planex Communications, Inc." } , + { 0x14EB, "", "Seiko Epson Corporation" } , + { 0x14EC, "", "Acqiris" } , + { 0x14ED, "", "Datakinetics Ltd" } , + { 0x14EF, "", "Carry Computer Eng. Co Ltd" } , + { 0x14F1, "Conexant", "Conexant" } , + { 0x14F2, "Mobility", "Mobility Electronics, Inc." } , + { 0x14F4, "", "Tokyo Electronic Industry Co. Ltd." } , + { 0x14F5, "", "Sopac Ltd" } , + { 0x14F6, "", "Coyote Technologies LLC" } , + { 0x14F7, "", "Wolf Technology Inc" } , + { 0x14F8, "", "Audiocodes Inc" } , + { 0x14F9, "", "AG Communications" } , + { 0x14FB, "", "Transas Marine (UK) Ltd" } , + { 0x14FC, "", "Quadrics Ltd" } , + { 0x14FD, "Silex", "Silex Technology Inc." } , + { 0x14FE, "", "Archtek Telecom Corp." } , + { 0x14FF, "", "Twinhead International Corp." } , + { 0x1501, "", "Banksoft Canada Ltd" } , + { 0x1502, "", "Mitsubishi Electric Logistics Support Co" } , + { 0x1503, "", "Kawasaki LSI USA Inc" } , + { 0x1504, "", "Kaiser Electronics" } , + { 0x1506, "", "Chameleon Systems Inc" } , + { 0x1507, "Htec", "Htec Ltd." } , + { 0x1509, "FIC", "First International Computer Inc" } , + { 0x150B, "", "Yamashita Systems Corp" } , + { 0x150C, "", "Kyopal Co Ltd" } , + { 0x150D, "", "Warpspped Inc" } , + { 0x150E, "", "C-Port Corporation" } , + { 0x150F, "", "Intec GMBH" } , + { 0x1510, "", "Behavior Tech Computer Corp" } , + { 0x1511, "", "Centillium Technology Corp" } , + { 0x1512, "Rosen", "Rosun Technologies Inc" } , + { 0x1513, "", "Raychem" } , + { 0x1514, "", "TFL LAN Inc" } , + { 0x1515, "", "ICS Advent" } , + { 0x1516, "", "Myson Technology Inc" } , + { 0x1517, "", "Echotek Corporation" } , + { 0x1518, "", "Kontron Modular Computers GmbH (PEP Modular Computers GMBH)" } , + { 0x1519, "", "Telefon Aktiebolaget LM Ericsson" } , + { 0x151A, "Globetek", "Globetek Inc." } , + { 0x151B, "wesam", "Combox Ltd" } , + { 0x151C, "", "Digital Audio Labs Inc" } , + { 0x151D, "", "Fujitsu Computer Products Of America" } , + { 0x151E, "", "Matrix Corp." } , + { 0x151F, "", "Topic Semiconductor Corp" } , + { 0x1520, "", "Chaplet System Inc" } , + { 0x1521, "", "Bell Corporation" } , + { 0x1522, "Mainpine", "Mainpine Limited" } , + { 0x1523, "", "Music Semiconductors" } , + { 0x1524, "mayer", "ENE Technology Inc" } , + { 0x1525, "", "Impact Technologies" } , + { 0x1526, "", "ISS Inc" } , + { 0x1527, "", "Solectron" } , + { 0x1528, "", "Acksys" } , + { 0x1529, "", "American Microsystems Inc" } , + { 0x152A, "", "Quickturn Design Systems" } , + { 0x152B, "", "Flytech Technology Co Ltd" } , + { 0x152C, "", "Macraigor Systems LLC" } , + { 0x152D, "", "Quanta Computer Inc" } , + { 0x152E, "", "Melec Inc" } , + { 0x152F, "", "Philips - Crypto" } , + { 0x1532, "", "Echelon Corporation" } , + { 0x1533, "", "Baltimore" } , + { 0x1534, "", "Road Corporation" } , + { 0x1535, "", "Evergreen Technologies Inc" } , + { 0x1537, "", "Datalex Communcations" } , + { 0x1538, "Aralion", "Aralion Inc." } , + { 0x1539, "", "Atelier Informatiques et Electronique Et" } , + { 0x153A, "", "ONO Sokki" } , + { 0x153B, "cami", "Terratec Electronic GMBH" } , + { 0x153C, "", "Antal Electronic" } , + { 0x153D, "", "Filanet Corporation" } , + { 0x153E, "Techwell", "Techwell Inc" } , + { 0x153F, "MIPS", "MIPS Technologies, Inc" } , + { 0x1540, "", "Provideo Multimedia Co Ltd" } , + { 0x1541, "", "Telocity Inc." } , + { 0x1542, "", "Vivid Technology Inc" } , + { 0x1543, "", "Silicon Laboratories" } , + { 0x1544, "DCM", "DCM Technologies Ltd." } , + { 0x1545, "Visiontek", "VisionTek" } , + { 0x1546, "", "IOI Technology Corp." } , + { 0x1547, "", "Mitutoyo Corporation" } , + { 0x1548, "", "Jet Propulsion Laboratory" } , + { 0x1549, "ISS", "Interconnect Systems Solutions" } , + { 0x154A, "", "Max Technologies Inc." } , + { 0x154B, "", "Computex Co Ltd" } , + { 0x154C, "", "Visual Technology Inc." } , + { 0x154D, "", "PAN International Industrial Corp" } , + { 0x154E, "", "Servotest Ltd" } , + { 0x154F, "", "Stratabeam Technology" } , + { 0x1550, "", "Open Network Co Ltd" } , + { 0x1551, "", "Smart Electronic Development GMBH" } , + { 0x1553, "", "Chicony Electronics Co Ltd" } , + { 0x1554, "PMC", "Prolink Microsystems Corp." } , + { 0x1555, "Gesytec", "Gesytec GmbH" } , + { 0x1556, "", "PLD Applications" } , + { 0x1557, "", "Mediastar Co. Ltd" } , + { 0x1558, "", "Clevo/Kapok Computer" } , + { 0x1559, "", "SI Logic Ltd" } , + { 0x155A, "", "Innomedia Inc" } , + { 0x155B, "", "Protac International Corp" } , + { 0x155C, "", "s" } , + { 0x155D, "", "MAC System Co Ltd" } , + { 0x155E, "KR", "KUKA Roboter GmbH" } , + { 0x155F, "", "Perle Systems Limited" } , + { 0x1560, "", "Terayon Communications Systems" } , + { 0x1561, "", "Viewgraphics Inc" } , + { 0x1562, "", "Symbol Technologies, Inc." } , + { 0x1563, "", "A-Trend Technology Co Ltd" } , + { 0x1564, "", "Yamakatsu Electronics Industry Co Ltd" } , + { 0x1565, "xyz", "Biostar Microtech Intl Corp" } , + { 0x1566, "", "Ardent Technologies Inc" } , + { 0x1567, "", "Jungsoft" } , + { 0x1568, "", "DDK Electronics Inc" } , + { 0x1569, "AleksSPb", "Palit Microsystems Inc" } , + { 0x156A, "Avtec", "Avtec Systems Inc" } , + { 0x156B, "", "S2io Inc" } , + { 0x156C, "", "Vidac Electronics GMBH" } , + { 0x156D, "", "Alpha-Top Corp" } , + { 0x156E, "", "Alfa Inc." } , + { 0x156F, "", "M-Systems Flash Disk Pioneers Ltd" } , + { 0x1570, "", "Lecroy Corporation" } , + { 0x1571, "", "Contemporary Controls" } , + { 0x1572, "", "Otis Elevator Company" } , + { 0x1573, "", "Lattice - Vantis" } , + { 0x1574, "", "Fairchild Semiconductor" } , + { 0x1575, "", "Voltaire Advanced Data Security Ltd" } , + { 0x1576, "", "Viewcast Com" } , + { 0x1578, "", "Hitt" } , + { 0x1579, "", "Dual Technology Corporation" } , + { 0x157A, "", "Japan Elecronics Ind. Inc" } , + { 0x157B, "", "Star Multimedia Corp." } , + { 0x157C, "Eurosoft", "Eurosoft (UK)" } , + { 0x157D, "", "Gemflex Networks" } , + { 0x157E, "", "Transition Networks" } , + { 0x157F, "", "PX Instruments Technology Ltd" } , + { 0x1580, "", "Primex Aerospace Co." } , + { 0x1581, "", "SEH Computertechnik GMBH" } , + { 0x1582, "", "Cytec Corporation" } , + { 0x1583, "", "Inet Technologies Inc" } , + { 0x1584, "", "Uniwill Computer Corp." } , + { 0x1585, "", "Marconi Commerce Systems SRL" } , + { 0x1586, "", "Lancast Inc" } , + { 0x1587, "", "Konica Corporation" } , + { 0x1588, "Solidum", "Solidum Systems Corp" } , + { 0x1589, "", "Atlantek Microsystems Pty Ltd" } , + { 0x158A, "", "Digalog Systems Inc" } , + { 0x158B, "", "Allied Data Technologies" } , + { 0x158C, "", "Hitachi Semiconductor & Devices Sales Co" } , + { 0x158D, "", "Point Multimedia Systems" } , + { 0x158E, "", "Lara Technology Inc" } , + { 0x158F, "", "Ditect Coop" } , + { 0x1590, "", "3pardata Inc." } , + { 0x1591, "", "ARN" } , + { 0x1592, "Syba", "Syba Tech Ltd." } , + { 0x1593, "", "Bops Inc" } , + { 0x1594, "", "Netgame Ltd" } , + { 0x1595, "", "Diva Systems Corp." } , + { 0x1596, "", "Folsom Research Inc" } , + { 0x1597, "", "Memec Design Services" } , + { 0x1598, "", "Granite Microsystems" } , + { 0x1599, "", "Delta Electronics Inc" } , + { 0x159A, "", "General Instrument" } , + { 0x159B, "", "Faraday Technology Corp" } , + { 0x159C, "", "Stratus Computer Systems" } , + { 0x159D, "", "Ningbo Harrison Electronics Co Ltd" } , + { 0x159E, "", "A-Max Technology Co Ltd" } , + { 0x159F, "", "Galea Network Security" } , + { 0x15A0, "", "Compumaster SRL" } , + { 0x15A1, "", "Geocast Network Systems Inc" } , + { 0x15A2, "", "Catalyst Enterprises Inc" } , + { 0x15A3, "", "Italtel" } , + { 0x15A4, "", "X-Net OY" } , + { 0x15A5, "", "Toyota MACS Inc" } , + { 0x15A6, "", "Sunlight Ultrasound Technologies Ltd" } , + { 0x15A7, "", "SSE Telecom Inc" } , + { 0x15A8, "", "Shanghai Communications Technologies Cen" } , + { 0x15AA, "", "Moreton Bay" } , + { 0x15AB, "", "Bluesteel Networks Inc" } , + { 0x15AC, "", "North Atlantic Instruments" } , + { 0x15AD, "VMware", "VMware Inc." } , + { 0x15AE, "", "Amersham Pharmacia Biotech" } , + { 0x15B0, "", "Zoltrix International Limited" } , + { 0x15B1, "", "Source Technology Inc" } , + { 0x15B2, "", "Mosaid Technologies Inc." } , + { 0x15B3, "", "Mellanox Technology" } , + { 0x15B4, "", "CCI/Triad" } , + { 0x15B5, "", "Cimetrics Inc" } , + { 0x15B6, "", "Texas Memory Systems Inc" } , + { 0x15B7, "", "Sandisk Corp." } , + { 0x15B8, "", "Addi-Data GMBH" } , + { 0x15B9, "", "Maestro Digital Communications" } , + { 0x15BA, "", "Impacct Technology Corp" } , + { 0x15BB, "", "Portwell Inc" } , + { 0x15BC, "Agilent", "Agilent Technologies" } , + { 0x15BD, "", "DFI Inc." } , + { 0x15BE, "", "Sola Electronics" } , + { 0x15BF, "", "High Tech Computer Corp (HTC)" } , + { 0x15C0, "BVM", "BVM Limited" } , + { 0x15C1, "", "Quantel" } , + { 0x15C2, "", "Newer Technology Inc" } , + { 0x15C3, "", "Taiwan Mycomp Co Ltd" } , + { 0x15C4, "", "EVSX Inc" } , + { 0x15C5, "", "Procomp Informatics Ltd" } , + { 0x15C6, "", "Technical University Of Budapest" } , + { 0x15C7, "", "Tateyama System Laboratory Co Ltd" } , + { 0x15C8, "", "Penta Media Co. Ltd" } , + { 0x15C9, "", "Serome Technology Inc" } , + { 0x15CA, "", "Bitboys OY" } , + { 0x15CB, "", "AG Electronics Ltd" } , + { 0x15CC, "", "Hotrail Inc." } , + { 0x15CD, "", "Dreamtech Co Ltd" } , + { 0x15CE, "", "Genrad Inc." } , + { 0x15CF, "", "Hilscher GMBH" } , + { 0x15D1, "Infineon", "Infineon Technologies AG" } , + { 0x15D2, "", "FIC (First International Computer Inc)" } , + { 0x15D3, "", "NDS Technologies Israel Ltd" } , + { 0x15D4, "", "Iwill Corporation" } , + { 0x15D5, "", "Tatung Co." } , + { 0x15D6, "", "Entridia Corporation" } , + { 0x15D7, "", "Rockwell-Collins Inc" } , + { 0x15D8, "", "Cybernetics Technology Co Ltd" } , + { 0x15D9, "", "Super Micro Computer Inc" } , + { 0x15DA, "", "Cyberfirm Inc." } , + { 0x15DB, "", "Applied Computing Systems Inc." } , + { 0x15DC, "Litronic", "Litronic Inc." } , + { 0x15DD, "jjk", "Sigmatel Inc." } , + { 0x15DE, "", "Malleable Technologies Inc" } , + { 0x15E0, "", "Cacheflow Inc" } , + { 0x15E1, "VTG", "Voice Technologies Group" } , + { 0x15E2, "", "Quicknet Technologies Inc" } , + { 0x15E3, "", "Networth Technologies Inc" } , + { 0x15E4, "", "VSN Systemen BV" } , + { 0x15E5, "", "Valley Technologies Inc" } , + { 0x15E6, "", "Agere Inc." } , + { 0x15E7, "", "GET Engineering Corp." } , + { 0x15E8, "", "National Datacomm Corp." } , + { 0x15E9, "", "Pacific Digital Corp." } , + { 0x15EA, "", "Tokyo Denshi Sekei K.K." } , + { 0x15EB, "", "Drsearch GMBH" } , + { 0x15EC, "", "Beckhoff GMBH" } , + { 0x15ED, "", "Macrolink Inc" } , + { 0x15EE, "", "IN Win Development Inc." } , + { 0x15EF, "", "Intelligent Paradigm Inc" } , + { 0x15F0, "", "B-Tree Systems Inc" } , + { 0x15F1, "", "Times N Systems Inc" } , + { 0x15F2, "", "Diagnostic Instruments Inc" } , + { 0x15F3, "", "Digitmedia Corp." } , + { 0x15F4, "", "Valuesoft" } , + { 0x15F5, "", "Power Micro Research" } , + { 0x15F6, "", "Extreme Packet Device Inc" } , + { 0x15F7, "", "Banctec" } , + { 0x15F8, "", "Koga Electronics Co" } , + { 0x15F9, "", "Zenith Electronics Co" } , + { 0x15FA, "Axzam", "Axzam Corporation" } , + { 0x15FB, "", "Zilog Inc." } , + { 0x15FC, "", "Techsan Electronics Co Ltd" } , + { 0x15FD, "", "N-Cubed.Net" } , + { 0x15FE, "", "Kinpo Electronics Inc" } , + { 0x15FF, "", "Fastpoint Technologies Inc." } , + { 0x1600, "", "Northrop Grumman - Canada Ltd" } , + { 0x1601, "", "Tenta Technology" } , + { 0x1602, "", "Prosys-TEC Inc." } , + { 0x1603, "", "Nokia Wireless Business Communications" } , + { 0x1604, "", "Central System Research Co Ltd" } , + { 0x1605, "", "Pairgain Technologies" } , + { 0x1606, "", "Europop AG" } , + { 0x1607, "", "Lava Semiconductor Manufacturing Inc." } , + { 0x1608, "", "Automated Wagering International" } , + { 0x1609, "", "Sciemetric Instruments Inc" } , + { 0x160A, "", "Kollmorgen Servotronix" } , + { 0x160B, "", "Onkyo Corp." } , + { 0x160C, "", "Oregon Micro Systems Inc." } , + { 0x160D, "", "Aaeon Electronics Inc" } , + { 0x160E, "", "CML Emergency Services" } , + { 0x160F, "", "ITEC Co Ltd" } , + { 0x1610, "", "Tottori Sanyo Electric Co Ltd" } , + { 0x1611, "", "Bel Fuse Inc." } , + { 0x1612, "", "Telesynergy Research Inc." } , + { 0x1613, "", "System Craft Inc." } , + { 0x1614, "", "Jace Tech Inc." } , + { 0x1615, "", "Equus Computer Systems Inc" } , + { 0x1616, "", "Iotech Inc." } , + { 0x1617, "", "Rapidstream Inc" } , + { 0x1618, "", "Esec SA" } , + { 0x1619, "FarSite", "FarSite Communications Limited" } , + { 0x161B, "", "Mobilian Israel Ltd" } , + { 0x161C, "", "Berkshire Products" } , + { 0x161D, "", "Gatec" } , + { 0x161E, "", "Kyoei Sangyo Co Ltd" } , + { 0x161F, "Arima", "Arima Computer Corporation" } , + { 0x1620, "", "Sigmacom Co Ltd" } , + { 0x1621, "", "Lynx Studio Technology Inc" } , + { 0x1622, "NHC", "Nokia Home Communications" } , + { 0x1623, "", "KRF Tech Ltd" } , + { 0x1624, "", "CE Infosys GMBH" } , + { 0x1625, "", "Warp Nine Engineering" } , + { 0x1626, "", "TDK Semiconductor Corp." } , + { 0x1627, "", "BCom Electronics Inc" } , + { 0x1629, "", "Kongsberg Spacetec a.s." } , + { 0x162A, "", "Sejin Computerland Co Ltd" } , + { 0x162B, "", "Shanghai Bell Company Limited" } , + { 0x162C, "", "C&H Technologies Inc" } , + { 0x162D, "", "Reprosoft Co Ltd" } , + { 0x162E, "", "Margi Systems Inc" } , + { 0x162F, "", "Rohde & Schwarz GMBH & Co KG" } , + { 0x1630, "", "Sky Computers Inc" } , + { 0x1631, "", "NEC Computer International" } , + { 0x1632, "", "Verisys Inc" } , + { 0x1633, "", "Adac Corporation" } , + { 0x1634, "", "Visionglobal Network Corp." } , + { 0x1635, "", "Decros" } , + { 0x1636, "", "Jean Company Ltd" } , + { 0x1637, "", "NSI" } , + { 0x1638, " Eumitcom Technology Inc", "Eumitcom Technology Inc" } , + { 0x163A, "", "Air Prime Inc" } , + { 0x163B, "", "Glotrex Co Ltd" } , + { 0x163C, "", "intel" } , + { 0x163D, "", "Heidelberg Digital LLC" } , + { 0x163E, "владими&", "3dpower" } , + { 0x163F, "", "Renishaw PLC" } , + { 0x1640, "", "Intelliworxx Inc" } , + { 0x1641, "", "MKNet Corporation" } , + { 0x1642, "", "Bitland" } , + { 0x1643, "", "Hajime Industries Ltd" } , + { 0x1644, "", "Western Avionics Ltd" } , + { 0x1645, "", "Quick-Serv. Computer Co. Ltd" } , + { 0x1646, "", "Nippon Systemware Co Ltd" } , + { 0x1647, "", "Hertz Systemtechnik GMBH" } , + { 0x1648, "", "MeltDown Systems LLC" } , + { 0x1649, "", "Jupiter Systems" } , + { 0x164A, "", "Aiwa Co. Ltd" } , + { 0x164C, "", "Department Of Defense" } , + { 0x164D, "", "Ishoni Networks" } , + { 0x164E, "", "Micrel Inc." } , + { 0x164F, "DataVoice", "Datavoice (Pty) Ltd." } , + { 0x1650, "", "Admore Technology Inc." } , + { 0x1651, "", "Chaparral Network Storage" } , + { 0x1652, "", "Spectrum Digital Inc." } , + { 0x1653, "Naturetech", "Nature Worldwide Technology Corp" } , + { 0x1654, "", "Sonicwall Inc" } , + { 0x1655, "", "Dazzle Multimedia Inc." } , + { 0x1656, "", "Insyde Software Corp" } , + { 0x1657, "", "Brocade Communications Systems" } , + { 0x1658, "", "Med Associates Inc." } , + { 0x1659, "", "Shiba Denshi Systems Inc." } , + { 0x165A, "", "Epix Inc." } , + { 0x165B, "", "Real-Time Digital Inc." } , + { 0x165C, "", "Kondo Kagaku" } , + { 0x165D, "", "Hsing Tech. Enterprise Co. Ltd." } , + { 0x165E, "", "Hyunju Computer Co. Ltd." } , + { 0x165F, "Comart", "Comartsystem Korea" } , + { 0x1660, "", "Network Security Technologies Inc. (Net" } , + { 0x1661, "", "Worldspace Corp." } , + { 0x1662, "", "Int Labs" } , + { 0x1663, "", "Elmec Inc. Ltd." } , + { 0x1664, "", "Fastfame Technology Co. Ltd." } , + { 0x1665, "", "Edax Inc." } , + { 0x1666, "", "Norpak Corporation" } , + { 0x1667, "", "CoSystems Inc." } , + { 0x1668, "Actiontec", "Actiontec Electronics Inc." } , + { 0x166A, "", "Komatsu Ltd." } , + { 0x166B, "", "Supernet Inc." } , + { 0x166C, "", "Shade Ltd." } , + { 0x166D, "", "Sibyte Inc." } , + { 0x166E, "", "Schneider Automation Inc." } , + { 0x166F, "", "Televox Software Inc." } , + { 0x1670, "", "Rearden Steel" } , + { 0x1671, "", "Atan Technology Inc." } , + { 0x1672, "", "Unitec Co. Ltd." } , + { 0x1673, "", "pctel" } , + { 0x1675, "", "Square Wave Technology" } , + { 0x1676, "Gateway", "Emachines Inc." } , + { 0x1677, "", "Bernecker + Rainer" } , + { 0x1678, "", "INH Semiconductor" } , + { 0x1679, "", "Tokyo Electron Device Ltd." } , + { 0x167F, "iba", "iba AG" } , + { 0x1680, "Dunti", "Dunti Corp." } , + { 0x1681, "Hercules", "Hercules" } , + { 0x1682, "PINE", "PINE Technology, Ltd." } , + { 0x1688, "CastleNet", "CastleNet Technology Inc." } , + { 0x168A, "USA", "Utimaco Safeware AG" } , + { 0x168B, "", "Circut Assembly Corp." } , + { 0x168C, "Atheros", "Atheros Communications Inc." } , + { 0x168D, "NMI", "NMI Electronics Ltd." } , + { 0x168E, "Hyundai MultiCAV", "Hyundai MultiCAV Computer Co. Ltd." } , + { 0x168F, "qsb", "KDS Innotech Corp." } , + { 0x1690, "NetContinuum", "NetContinuum, Inc." } , + { 0x1693, "FERMA", "FERMA" } , + { 0x1695, "EPoX", "EPoX Computer Co., Ltd." } , + { 0x16AE, "SFNT", "SafeNet Inc." } , + { 0x16B3, "", "CNF Mobile Solutions" } , + { 0x16B8, "Sonnet Technologies", "Sonnet Technologies, Inc." } , + { 0x16CA, "Cenatek", "Cenatek Inc." } , + { 0x16CB, "Minolta", "Minolta Co. Ltd." } , + { 0x16CC, "Inari", "Inari Inc." } , + { 0x16D0, "", "Systemax" } , + { 0x16E0, "3MTS", "Third Millenium Test Solutions, Inc." } , + { 0x16E5, "", "Intellon Corporation" } , + { 0x16EC, "USR", "U.S. Robotics" } , + { 0x16F0, "", "TLA Inc." } , + { 0x16F1, "Adicti", "Adicti Corp." } , + { 0x16F3, "Jetway", "Jetway Information Co., Ltd" } , + { 0x16F6, "VideoTele.com", "VideoTele.com Inc." } , + { 0x1700, "Antara", "Antara LLC" } , + { 0x1701, "", "Interactive Computer Products Inc." } , + { 0x1702, "IMC", "Internet Machines Corp." } , + { 0x1703, "Desana", "Desana Systems" } , + { 0x1704, "Clearwater", "Clearwater Networks" } , + { 0x1705, "Digital First", "Digital First" } , + { 0x1706, "PBC", "Pacific Broadband Communications" } , + { 0x1707, "Cogency", "Cogency Semiconductor Inc." } , + { 0x1708, "Harris", "Harris Corp." } , + { 0x1709, "Zarlink", "Zarlink Semiconductor" } , + { 0x170A, "Alpine", "Alpine Electronics Inc." } , + { 0x170B, "NetOctave", "NetOctave Inc." } , + { 0x170C, "YottaYotta", "YottaYotta Inc." } , + { 0x170D, "SMI", "SensoMotoric Instruments GmbH" } , + { 0x170E, "San Valley", "San Valley Systems, Inc." } , + { 0x170F, "Cyberdyne", "Cyberdyne Inc." } , + { 0x1710, "Pelago", "Pelago Nutworks" } , + { 0x1711, "NetScreen", "MyName Technologies, Inc." } , + { 0x1712, "NICE", "NICE Systems Inc." } , + { 0x1713, "TOPCON", "TOPCON Corp." } , + { 0x1725, "Vitesse", "Vitesse Semiconductor" } , + { 0x1734, "Fujitsu-Siemens", "Fujitsu-Siemens Computers GmbH" } , + { 0x1737, "LinkSys", "LinkSys" } , + { 0x173B, "Altima", "Altima Communications Inc." } , + { 0x1743, "Peppercon", "Peppercon AG" } , + { 0x174B, "PC Partner (Sapphire)", "PC Partner Limited" } , + { 0x1752, "AMW Europe GmbH", "Global Brands Manufacture Ltd." } , + { 0x1753, "TeraRecon", "TeraRecon, Inc." } , + { 0x1755, "Alchemy", "Alchemy Semiconductor Inc." } , + { 0x176A, "GDC", "General Dynamics Canada" } , + { 0x1789, "Ennyah", "Ennyah Technologies Corp" } , + { 0x1793, "Unitech", "Unitech Electronics Co., Ltd" } , + { 0x17A7, "Start Network", "Start Network Technology Co., Ltd." } , + { 0x17AA, "lenovo", "Legend Ltd. (Beijing)" } , + { 0x17AB, "", "Phillips Components" } , + { 0x17AF, "Hightech", "Hightech Information Systems, Ltd." } , + { 0x17BE, "Philips", "Philips Semiconductors" } , + { 0x17C0, "Wistron", "Wistron Corp." } , + { 0x17C4, "", "Movita" } , + { 0x17CC, "NetChip", "NetChip" } , + { 0x17D5, "Neterion", "Neterion Inc." } , + { 0x17E9, "", "DH electronics GmbH" } , + { 0x17EE, "Connect3D", "Connect Components, Ltd." } , + { 0x1813, "Ambient", "phillip rees" } , + { 0x1814, "Ralink Technology", "Ralink Technology, Corp" } , + { 0x1815, "devolo", "devolo AG" } , + { 0x1820, "InfiniCon", "InfiniCon Systems, Inc." } , + { 0x1824, "Avocent", "Avocent" } , + { 0x1860, "Primagraphics", "Primagraphics Ltd." } , + { 0x186C, "Humusoft", "Humusoft S.R.O" } , + { 0x1887, "Elan", "Elan Digital Systems Ltd" } , + { 0x1888, "", "Varisys Limited" } , + { 0x188D, "Millogic", "Millogic Ltd." } , + { 0x1890, "", "Egenera, Inc." } , + { 0x18BC, "", "Info-Tek Corp." } , + { 0x18C9, "ARVOO", "ARVOO Engineering BV" } , + { 0x18CA, "XGI", "XGI Technology Inc" } , + { 0x18F1, "Spc", "Spectrum Systementwicklung Microelectronic GmbH" } , + { 0x18F4, "Napatech", "Napatech A/S" } , + { 0x18F7, "Commtech", "Commtech, Inc." } , + { 0x18FB, "", "Resilience Corporation" } , + { 0x1905, "WIS Computers", "WIS Technology, Inc." } , + { 0x1910, "Seaway Networks", "Seaway Networks" } , + { 0x1971, "", "AGEIA Technologies, Inc." } , + { 0x19A8, "DAQDATA", "DAQDATA GmbH" } , + { 0x19AC, "Kasten Chase", "Kasten Chase Applied Research" } , + { 0x19E2, "Vector", "Vector Informatik GmbH" } , + { 0x1A08, "", "Linux Networx" } , + { 0x1A42, "", "Imaginant" } , + { 0x1B13, "Jaton Corp", "Jaton Corporation USA" } , + { 0x1DE1, "Tekram", "Tekram" } , + { 0x1FCF, "Miranda", "Miranda Technologies Ltd." } , + { 0x2001, "", "Temporal Research Ltd" } , + { 0x2646, "Kingston", "Kingston Technology Co." } , + { 0x270F, "ChainTech", "ChainTech Computer Co. Ltd." } , + { 0x2EC1, "", "Zenic Inc" } , + { 0x3388, "Hint", "Hint Corp." } , + { 0x3411, "", "Quantum Designs (H.K.) Inc." } , + { 0x3513, "ARCOM", "ARCOM Control Systems Ltd." } , + { 0x38EF, "", "4links" } , + { 0x3D3D, "3DLabs", "3Dlabs, Inc. Ltd" } , + { 0x4005, "Avance", "Avance Logic Inc." } , + { 0x4144, "Alpha Data", "Alpha Data" } , + { 0x416C, "", "Aladdin Knowledge Systems" } , + { 0x4680, "UMAX Comp", "UMAX Computer Corp." } , + { 0x4843, "Hercules", "Hercules Computer Technology" } , + { 0x4943, "", "Growth Networks" } , + { 0x4954, "Integral", "Integral Technologies" } , + { 0x4978, "Axil", "Axil Computer Inc." } , + { 0x4C48, "Lung Hwa", "Lung Hwa Electronics" } , + { 0x4C53, "SBS", "SBS-OR Industrial Computers" } , + { 0x4CA1, "", "Seanix Technology Inc" } , + { 0x4D51, "Mediaq", "Mediaq Inc." } , + { 0x4D54, "", "Microtechnica Co Ltd" } , + { 0x4DDC, "ILC", "ILC Data Device Corp." } , + { 0x5053, "TBS/Voyetra", "TBS/Voyetra Technologies" } , + { 0x5136, "", "S S Technologies" } , + { 0x5143, "Qualcomm", "Qualcomm Inc." } , + { 0x5333, "S3 86c765", "S3 Graphics Co., Ltd" } , + { 0x544C, "", "Teralogic Inc" } , + { 0x5555, "Genroco", "Genroco Inc." } , + { 0x6409, "", "Logitec Corp." } , + { 0x6666, "Decision", "Decision Computer International Co." } , + { 0x7604, "O.N.", "O.N. Electric Co. Ltd." } , + { 0x8086, "Intel", "Intel Corporation" } , + { 0x80EE, "VirtualBox", "VirtualBox" } , + { 0x8866, "T-Square", "T-Square Design Inc." } , + { 0x8888, "Sil Magic", "Silicon Magic" } , + { 0x8E0E, "Computone", "Computone Corporation" } , + { 0x9004, "Adaptec", "Adaptec Inc" } , + { 0x9005, "Adaptec", "Adaptec Inc" } , + { 0x919A, "", "Gigapixel Corp" } , + { 0x9412, "Holtek", "Holtek" } , + { 0x9699, "", "Omni Media Technology Inc." } , + { 0x9902, "StarGen", "StarGen, Inc." } , + { 0xA0A0, "Aopen", "Aopen Inc." } , + { 0xA0F1, "", "Unisys Corporation" } , + { 0xA200, "NEC", "NEC Corp." } , + { 0xA259, "", "Hewlett Packard" } , + { 0xA304, "Sony", "Sony" } , + { 0xA727, "", "3com Corporation" } , + { 0xAA42, "Scitex", "Scitex Digital Video" } , + { 0xAC1E, "", "Digital Receiver Technology Inc" } , + { 0xB1B3, "Shiva", "Shiva Europe Ltd." } , + { 0xB894, "", "Brown & Sharpe Mfg. Co." } , + { 0xBEEF, "Mindstream Computing", "Mindstream Computing" } , + { 0xC001, "TSI", "TSI Telsys" } , + { 0xC0A9, "Micron/Crucial", "Micron/Crucial Technology" } , + { 0xC0DE, "", "Motorola" } , + { 0xC0FE, "Mot Engrg", "Motion Engineering Inc." } , + { 0xC622, "", "Hudson Soft Co Ltd" } , + { 0xCA50, "Varian", "Varian, Inc" } , + { 0xCAFE, "", "Chrysalis-ITS" } , + { 0xCCCC, "", "Catapult Communications" } , + { 0xD4D4, "Processing", "Curtiss-Wright Controls Embedded Computing" } , + { 0xDC93, "", "Dawicontrol" } , + { 0xDEAD, "Indigita", "Indigita Corporation" } , + { 0xDEAF, "", "Middle Digital, Inc" } , + { 0xE159, "Tiger Jet", "Tiger Jet Network Inc" } , + { 0xE4BF, "", "EKF Elektronik GMBH" } , + { 0xEA01, "", "Eagle Technology" } , + { 0xEABB, "Aashima", "Aashima Technology B.V." } , + { 0xEACE, "Endace", "Endace Measurement Systems Ltd." } , + { 0xECC0, "Echo", "Echo Digital Audio Corporation" } , + { 0xEDD8, "ARK Logic", "ARK Logic, Inc" } , + { 0xF5F5, "", "F5 Networks Inc." } , + { 0xFA57, "Interagon", "Interagon AS" } , +} ; + + +// Use this value for loop control during searching: +#define PCI_VENTABLE_LEN (sizeof(PciVenTable)/sizeof(PCI_VENTABLE)) + +typedef struct _PCI_DEVTABLE +{ + unsigned short VenId ; + unsigned short DevId ; + const char * Chip ; + const char * ChipDesc ; +} PCI_DEVTABLE, *PPCI_DEVTABLE ; + +PCI_DEVTABLE PciDevTable [] = +{ + { 0x165C, 0x0002, "FT232BL", "FT232BL" } , + { 0x16AE, 0x1141, "SafeXcel-1141", "???" } , + { 0x11DB, 0x1234, "", "Dreamcast Broadband Adapter" } , + { 0x11DE, 0x6057, "ZR36067", "AV PCI Controller" } , + { 0x11DE, 0x6067, "zr36067pqc", "zoran" } , + { 0x11DE, 0x6120, "ZR36120PQC", "MPEG VideoBVPSXI Capture Card" } , + { 0x11DE, 0x6057, "ZR36057PQC", "ZORAN PCI Bridge (interface for transferring video across the PCI bus)" } , + { 0x11DE, 0x9876, "", "" } , + { 0x11EC, 0x2064, "", "" } , + { 0x11F0, 0x4231, "", "" } , + { 0x11F0, 0x4232, "FASTline UTP Quattro", "" } , + { 0x11F0, 0x4233, "FASTline FO", "" } , + { 0x11F0, 0x4234, "FASTline UTP", "" } , + { 0x11F0, 0x4235, "FASTline-II UTP", "" } , + { 0x11F0, 0x4236, "FASTline-II FO", "" } , + { 0x11F0, 0x4731, "GIGAline", "Gigabit Ethernet Adapter" } , + { 0x11F4, 0x2915, "2915", "" } , + { 0x11F6, 0x0112, "ATT2MD11", "ReadyLink ENET100-VG4" } , + { 0x11F6, 0x0113, "", "FreedomLine 100" } , + { 0x11F6, 0x1401, "832AE28030680", "ReadyLink RL2000" } , + { 0x11F6, 0x2011, "TXA9882", "ReadyLink RL100ATX/PCI Fast Ethernet Adapter" } , + { 0x11F6, 0x2201, "TXA9883", "ReadyLink 100TX (Winbond W89C840)" } , + { 0x11F6, 0x9881, "TXA9881?", "ReadyLink RL100TX Fast Ethernet Adapter" } , + { 0x11F8, 0x7364, "PM7364", "FREEDM-32 Frame Engine & Datalink Mgr" } , + { 0x11F8, 0x7366, "PM7364", "FREEDM-8 Frame Engine & Datalink Manager" } , + { 0x11F8, 0x7367, "PM7367", "FREEDM-32P32 Frame Engine & Datalink Mgr" } , + { 0x11F8, 0x7375, "PM7375", "LASAR-155 ATM SAR" } , + { 0x11F8, 0x7380, "PM7380", "FREEDM-32P672 Frm Engine & Datalink Mgr" } , + { 0x11F8, 0x7382, "PM7382", "FREEDM-32P256 Frm Engine & Datalink Mgr" } , + { 0x11F8, 0x7384, "PM7384", "FREEDM-84P672 Frm Engine & Datalink Mgr" } , + { 0x11F8, 0x8000, "PM8000 SPC", "6G SAS/SATA Controller" } , + { 0x11F8, 0x8010, "PM8010 SRC", "6G SAS/SATA RAID Controller" } , + { 0x11FE, 0x0001, "RocketPort", "" } , + { 0x11FE, 0x0002, "RocketPort", "" } , + { 0x11FE, 0x0003, "RocketPort", "" } , + { 0x11FE, 0x0004, "RocketPort", "" } , + { 0x11FE, 0x0005, "RocketPort", "" } , + { 0x11FE, 0x0006, "RocketPort", "" } , + { 0x11FE, 0x0007, "RocketPort", "" } , + { 0x11FE, 0x0008, "RocketPort", "" } , + { 0x11FE, 0x0009, "RocketPort", "" } , + { 0x11FE, 0x000A, "RocketPort", "" } , + { 0x11FE, 0x000B, "RocketPort", "" } , + { 0x11FE, 0x000C, "RocketPort", "" } , + { 0x11FE, 0x000D, "RocketPort", "" } , + { 0x11FE, 0x8015, "RocketPort", "4-port UART 16954" } , + { 0x1202, 0x0001, "NAIATMPCI", "PCI ATM Adapter" } , + { 0x1208, 0x4853, "", "HS-Link Device" } , + { 0x1365, 0x9050, "HYSDN", "" } , + { 0x1209, 0x0100, "PCI 9054", "PLX PCI BRIDGE" } , + { 0x120E, 0x0100, "Cyclom-Y", "Multiport Serial Card" } , + { 0x120E, 0x0101, "Cyclom-Y", "Multiport Serial Card" } , + { 0x120E, 0x0102, "Cyclom-4Y", "Multiport Serial Card" } , + { 0x120E, 0x0103, "Cyclom-4Y", "Multiport Serial Card" } , + { 0x120E, 0x0104, "Cyclom-8Y", "Multiport Serial Card" } , + { 0x120E, 0x0105, "Cyclom-8Y", "Multiport Serial Card" } , + { 0x120E, 0x0200, "Cyclom-Z", "Intelligent Multiport Serial" } , + { 0x120E, 0x0201, "Cyclom-Z", "Intelligent Serial Card" } , + { 0x120E, 0x0300, "PC300 RX 2", "" } , + { 0x120E, 0x0301, "PC300 RX 1", "" } , + { 0x120E, 0x0302, "PC300 TE 2", "" } , + { 0x120E, 0x0303, "PC300 TE 1", "" } , + { 0x120F, 0x0001, "Roadrunner", "" } , + { 0x1216, 0x0003, "?", "PTM400 PCI Taxi Module" } , + { 0x1217, 0x00f7, "0x00f71217", "1394 Open Host Controller Interface" } , + { 0x1217, 0x6729, "OZ6729", "PCI to PCMCIA Bridge" } , + { 0x1217, 0x673A, "OZ6730", "PCI to PCMCIA Bridge" } , + { 0x1217, 0x6832, "OZ6832/3", "CardBus Controller" } , + { 0x1217, 0x6836, "OZ6836/6860", "CardBus Controller" } , + { 0x1217, 0x6872, "OZ6812", "CardBus Controller" } , + { 0x1217, 0x6925, "OZ6922", "CardBus Controller" } , + { 0x1217, 0x6933, "OZ6933", "CardBus Controller" } , + { 0x1217, 0x6972, "OZ6912", "CardBus Controller" } , + { 0x1217, 0x7110, "OZ711Mx", "MemoryCardBus Accelerator" } , + { 0x1217, 0x7113, "0Z711EC1", "SmartCardBus Contoller" } , + { 0x1217, 0x7114, "OZ711M1", "CardBus Controller" } , + { 0x1217, 0x7120, "Unknown device", "O2Micro Integrated MMC/SD controller" } , + { 0x1217, 0x7130, "OZ711M3", "Integrated MMC/SD/MS/xD/SM Controller" } , + { 0x1217, 0x7134, "OZ711MP1/MS1", "MemoryCardBus Controller 6-in-1" } , + { 0x1217, 0x7222, "unknow", "pci to pcmcia bridge" } , + { 0x1217, 0x7223, "OZ711M3/MC3", "MemoryCardBus Controller" } , + { 0x121A, 0x0001, "Voodoo", "Voodoo 3D Acceleration Chip" } , + { 0x121A, 0x0002, "Voodoo2", "Voodoo 2 3D Accelerator" } , + { 0x121A, 0x0003, "Voodoo Banshee", "Voodoo Banshee" } , + { 0x121A, 0x0005, "Voodoo3", "All Voodoo3 chips, 3000" } , + { 0x121A, 0x0007, "Voodoo4", "" } , + { 0x121A, 0x0009, "Voodoo5", "" } , + { 0x121A, 0x0010, "Rampage", "Rev.A AGPx4, 0.25�, 200/2x200 core/RAM" } , + { 0x121A, 0x0057, "Voodoo 3/3000", "Avenger" } , + { 0x1220, 0x1220, "9622qac", "AMCC 5933 TMS320C80 DSP/Imaging Board" } , + { 0x1220, 0x4242, " ", "controller audio multimediale" } , + { 0x1223, 0x0001, "KatanaQp", "Real-Time Processing Blade in a standard single-slot AdvancedTCA� formfactor" } , + { 0x1223, 0x0002, "KosaiPM", "Intel� Pentium-M� based AMC Module" } , + { 0x1223, 0x003, "Katana3752", "Advanced Tri-Processor Blade" } , + { 0x1223, 0x004, "Katana3750", "Advanced Tri-Processor Blade" } , + { 0x1223, 0x0044, "Memory controller", "Memory controller" } , + { 0x1223, 0x005, "Katana752i", "Real-time Processing Blade" } , + { 0x1223, 0x006, "Katana750i", "Real-time Processing Blade" } , + { 0x1223, 0x007, "CC1000dm", "Processor PMC Carrier Card" } , + { 0x1223, 0x008, "Pm3Gv", "Up to 8 E1/T1/J1 interfaces for PMC-compatible baseboards" } , + { 0x1223, 0x009, "Pm3GE1T1", "Third Generation E1 and T1/J1 interfaces for PMC-compatible baseboards" } , + { 0x1223, 0x010, "SpiderwareSG", "SIGTRAN Signalling Gateway Blade" } , + { 0x1223, 0x011, "SpiderwareSS7", "64 SS7 signaling channels on a single blade" } , + { 0x1223, 0x012, "SpiderSS7", "Portable, STREAMS-Based Implementation of the ITU SS7 Protocol Stack" } , + { 0x1223, 0x013, "Spider FRAME RELAY", "STREAMS-Based Frame Relay Implementation" } , + { 0x1223, 0x014, "Spider STREAMS", "Implementation of the UNIX STREAMS Environment" } , + { 0x1223, 0x015, "Spider DSF", "Transparent STREAMS Interface for High Speed LAN or Shared Memory Systems" } , + { 0x1224, 0x1000, "CL560?", "Plum Audio, Video and VTR Controller" } , + { 0x122D, 0x1206, "ICH2", "Asus" } , + { 0x122D, 0x4201, "MR2800W", "AMR 56K modem" } , + { 0x122D, 0x50DC, "PCI168/3328", "Audio" } , + { 0x122D, 0x80DA, "3328", "Audio" } , + { 0x122F, 0x37AF, "0x9030", "Reflectometer using PLX 9030" } , + { 0x1668, 0x0100, "0304", "PCI to PCI Bridge" } , + { 0x1236, 0x0000, "RealMagic64/GX", "SD6425" } , + { 0x1236, 0x0531, "MX98715/25", "Single Chip Fast Ethernet NIC Controller" } , + { 0x1236, 0x3d01, "?", "RealMagic/2D" } , + { 0x1236, 0x6401, "REALmagic64/GX", "GUI" } , + { 0x1236, 0x9708, "realmagic64/gx", "sd6425" } , + { 0x123D, 0x0010, "PCI-DV", "PCI-DV Digital Video Interface" } , + { 0x123F, 0x00E4, "cl 480", "MPEG" } , + { 0x123F, 0x6120, "12.03", "DVD device" } , + { 0x123F, 0x8120, "176", "i845E" } , + { 0x123F, 0x8888, "12.03", "cPEG C 3.0 DVD/MPEG2 Decoder" } , + { 0x1241, 0x1603, "1", "keyboard" } , + { 0x1244, 0x0700, "B1", "ISDN controller" } , + { 0x1244, 0x0800, "C4", "ISDN Controller" } , + { 0x1244, 0x0A00, "A1", "ISDN Controller" } , + { 0x1244, 0x0E00, "", "Fritz!PCI 2.0 ISDN Controller" } , + { 0x1244, 0x1100, "C2", "ISDN Controller" } , + { 0x1244, 0x1200, "T1", "ISDN Controller" } , + { 0x1244, 0x2700, "E13 32A5KYW / 2CAKRCT", "DSP TNETD5100GHK / TNETD5015" } , + { 0x124A, 0x10BD, "82566DM-2", "Intel Gigabit network connection" } , + { 0x124C, 0x0220, ".", "." } , + { 0x124D, 0x0000, "EasyConnect 8/32", "" } , + { 0x124D, 0x0002, "EasyConnect 8/64", "" } , + { 0x124D, 0x0003, "EasyIO PCI", "" } , + { 0x124F, 0x0041, "IFT-2000", "PCI RAID Controller" } , + { 0x1250, 0x1978, "", "" } , + { 0x1250, 0x2898, "", "" } , + { 0x1255, 0x1110, "MPEG Forge", "" } , + { 0x1255, 0x1210, "MPEG Fusion", "" } , + { 0x1255, 0x2110, "VideoPlex-pci", "VideoPlex pci bpc1825 rev a" } , + { 0x1255, 0x2120, "VideoPlex plus", "VideoPlex BPC 1851 A" } , + { 0x1255, 0x2130, "VideoQuest", "" } , + { 0x1256, 0x4201, "PCI-2240i", "EIDE Adapter" } , + { 0x1256, 0x4401, "PCI-2220i", "Dale EIDE Adapter" } , + { 0x1256, 0x5201, "PCI-2000", "IntelliCache SCSI Adapter" } , + { 0x1258, 0x1988, "", "" } , + { 0x1259, 0x2503, "Realtek 8139b", "" } , + { 0x1259, 0x2560, "", "AT-2560 Fast Ethernet Adapter (i82557B)" } , + { 0x1259, 0xc107, "Realtek 8169S", "" } , + { 0x125B, 0x0B95, "AX88772", "USB2.0 to 10/100M Fast Ethernet Controller" } , + { 0x125B, 0x1400, "AX88140A", "ASIX AX88140 Based PCI Fast Ethernet Adapter" } , + { 0x125B, 0x1720, "AX88172", "USB2 to Fast Ethernet Adapter" } , + { 0x125D, 0x0000, "ESS336H", "PCI Fax Modem (early model)" } , + { 0x125D, 0x1961, "Multimedia Device", "ESS Solo-1 Soundcard" } , + { 0x125D, 0x1968, "ES2839", "Maestro-2 PCI audio accelerator" } , + { 0x125D, 0x1969, "ES72222", "Solo-1 PCI AudioDrive family" } , + { 0x125D, 0x1978, "ES1978", "ESS Maestro-2E PCI Audiodrive" } , + { 0x125D, 0x1988, "ES1989", "ESS Allegro PCI Audio (WDM)" } , + { 0x125D, 0x1989, "ES1989", "ESS Maestro 3 PCI Audio (WDM)" } , + { 0x125D, 0x1990, "ES2898S", "" } , + { 0x125D, 0x1992, "", "" } , + { 0x125D, 0x1998, "Maestro 3i", "Maestro 3i" } , + { 0x125D, 0x199B, "ES1938/41/46 solo audio", "Maestro-3.COMM PCI Voice+audio" } , + { 0x125D, 0x2808, "ES336H", "PCI Fax Modem (later model)" } , + { 0x125D, 0x2828, "ES2828S", "TeleDrive" } , + { 0x125D, 0x2838, "ES56H-PI", "Data Fax Modem" } , + { 0x125D, 0x2839, "2838", "Superlink Modem/V.92 chipset 56K" } , + { 0x125D, 0x2898, "2898", "TelDrive ES56T-PI family V.90 PCI modem" } , + { 0x125F, 0x2084, "AMCC S5933", "AMCC Bridge + 2 x Super I/O (National PC97338)" } , + { 0x1260, 0x3872, "PRISM 3", "LAN-Express IEEE 802.11b PCI Adapter" } , + { 0x1260, 0x3873, "ISL3874A", "PRISMII.5 IEE802.11B Wireless LAN" } , + { 0x1260, 0x3886, "Unknown", "Creatix CTX405 WLAN Controller" } , + { 0x1260, 0x3890, "ISL3890", "PRISM GT 802.11g 54Mbps Wireless Controller" } , + { 0x1260, 0x8130, "HMP8130", "NTSC/PAL Video Decoder" } , + { 0x1260, 0x8131, "HMP8131", "NTSC/PAL Video Decoder" } , + { 0x1266, 0x0001, "", "NE10/100 Adapter (i82557B)" } , + { 0x1266, 0x1910, "", "NE2000Plus (RT8029) Ethernet Adapter" } , + { 0x1267, 0x1016, "", "NICCY PCI card" } , + { 0x1267, 0x4243, "", "Satellite receiver board / MPEG2 decoder" } , + { 0x1267, 0x5352, "PCR2101", "" } , + { 0x1267, 0x5A4B, "telsatturbo", "" } , + { 0x1382, 0x0001, "unknown", "Sek'D ARC88 professional soundcard" } , + { 0x1382, 0x2009, "PLX TECHNOLOGY \n PCI9052 \n 0435 \n BX9497.1 MALA", "SEK'D Prodif 96 Pro - professional audio card" } , + { 0x1382, 0x2048, "2048", "Prodif Plus sound card" } , + { 0x1382, 0x2088, "Marc 8 Midi", "8-in, 8-out sound card" } , + { 0x1268, 0x0204, "Unknown", "Tektronix IO Processor / Tektronix PCI Acquisition Interface Rev 204" } , + { 0x126C, 0x1F1F, "", "e-mobility 802.11b Wireless LAN PCI Card" } , + { 0x126F, 0x0710, "SM710", "LynxEM" } , + { 0x126F, 0x0712, "SM712", "LynxEM+" } , + { 0x126F, 0x0720, "SM720 / SM722", "Lynx3DM" } , + { 0x126F, 0x0810, "SM810", "LynxE" } , + { 0x126F, 0x0811, "SM811", "LynxE" } , + { 0x126F, 0x0820, "SM820", "Lynx3D" } , + { 0x126F, 0x0910, "SM910", "SILICON MOTION" } , + { 0x1273, 0x0002, "DirecPC", "t9p17af-01" } , + { 0x1274, 0X1005, "", "" } , + { 0x1274, 0x1274, "5880x", "multimedia audio device" } , + { 0x1274, 0x1371, "ES 1371", "AudioPCI" } , + { 0x1274, 0x1373, "ES1373", "Sound Blaster Audio(PCI)" } , + { 0x1274, 0x5000, "ES1371", "AudioPCI" } , + { 0x1274, 0x5880, "5880x", "AudioPci" } , + { 0x1274, 0x9876, "", "" } , + { 0x1278, 0x0701, "TPE3/TM3", "PowerPC Node" } , + { 0x1279, 0x0060, "TM8000", "Efficeon Virtual Northbridge" } , + { 0x1279, 0x0061, "TMTM8000", "Efficeon AGP Bridge" } , + { 0x1279, 0x0295, "", "Virtual Northbridge" } , + { 0x1279, 0x0395, "LongRun", "Northbridge" } , + { 0x1279, 0x0396, "", "SDRAM Controller" } , + { 0x1279, 0x0397, "", "BIOS scratchpad" } , + { 0x1282, 0x9009, "DM9009", "Ethernet Adapter" } , + { 0x1282, 0x9100, "", "" } , + { 0x1282, 0x9102, "DM9102/A/AF", "10/100 Mbps Fast Ethernet Controller" } , + { 0x1283, 0x0801, "IT8152F/G", "Audio Digital Controller" } , + { 0x1283, 0x673A, "IT8330G", "IDE Controller" } , + { 0x1283, 0x8152, "IT8152F/G", "Advanced RISC-to-PCI Companion Chip" } , + { 0x1283, 0x8172, "IT8172G", "Ultra RISC (MIPS, SH4) Companion Chip" } , + { 0x1283, 0x8211, "IT8211F", "ATA/ATAPI Controller" } , + { 0x1283, 0x8212, "IT8212F", "ATA 133 IDE RAID Controller" } , + { 0x1283, 0x8213, "IT8213F", "IDE Controller" } , + { 0x1283, 0x8330, "IT8330G", "Host Bridge" } , + { 0x1283, 0x8872, "IT8871/72", "PCI-ISA I/O chip with SMB & Parallel Port" } , + { 0x1283, 0x8875, "IT8875F", "PCI Parallel Port" } , + { 0x1283, 0x8888, "IT8888F", "PCI to ISA Bridge" } , + { 0x1283, 0x8889, "IT8889F", "sound" } , + { 0x1283, 0x9876, "IT8875F", "PCI I/O CARD" } , + { 0x1283, 0xE886, "IT8330G", "PCI to ISA Bridge" } , + { 0x1285, 0x0100, "ES1849", "Maestro-1 AudioDrive" } , + { 0x1287, 0x001E, "LS220D", "DVD Decoder" } , + { 0x1287, 0x001F, "LS220C", "DVD Decoder" } , + { 0x1287, 0x0020, "LS242", "MPEG/DVD video decoder" } , + { 0x1289, 0x1006, "", "" } , + { 0x128A, 0xF001, "Ethernet 10/100", "AsanteFAST 10/100 PCI Ethernet Adapter" } , + { 0x128D, 0x0021, "", "ATM Adapter" } , + { 0x13FE, 0x1240, "PCI-1710", "4-Axis Stepping/Servo Motor Card" } , + { 0x13FE, 0x1680, "PCI-1680U-A", "2-port CAN UniversalPCI Communication Card with Isolation" } , + { 0x13FE, 0x1713, "PCI-1713", "32-channel Isolated Analog Input Card" } , + { 0x13FE, 0x1724, "PCI-1724", "14-bit, 32-channel Isolated Analog Output Card" } , + { 0x13FE, 0x1760, "", "" } , + { 0x129A, 0x0415, "PBT-415", "PCI 66MHz Analyzer and 33MHz Exerciser" } , + { 0x129A, 0x0515, "PBT-515", "PCI 66MHz Analyzer and Exerciser" } , + { 0x129A, 0x0615, "PBT-615", "PCI 66MHz and PCI-X 100MHz Bus Analyzer and Exerciser" } , + { 0x129A, 0x0715, "Vanguard PCI/PMC/cPCI", "PCI 66MHz and PCI-X 133MHz Bus Analyzer and Exerciser" } , + { 0x129A, 0xDD10, "DPIO", "Digital Parallel Input Output Device 32bit, 33MHz PCI bus" } , + { 0x129A, 0xDD11, "DPIO2", "Digital Parallel Input Output Device 64bit, 33MHz PCI bus" } , + { 0x129A, 0xDD12, "DPIO2-66", "Digital Parallel Input Output Device 64bit, 66MHz PCI bus" } , + { 0x12A0, 0x0008, "1784-PKTX", "Allen-Bradley 1784-PKTX" } , + { 0x12A3, 0xECB8, "1646T00", "V.92 Lucent Modem" } , + { 0x12AA, 0x5568, "Wan405", "WANic 400 series X.21 controller" } , + { 0x12AA, 0x556C, "", "NAI HSSI Sniffer PCI Adapter" } , + { 0x12AB, 0x3000, "JRS-3DS100", "PCI" } , + { 0x12AD, 0x0010, "1", "HERMES-S0" } , + { 0x12AD, 0x0020, "1", "HERMES-PRI" } , + { 0x12AD, 0x0080, "1", "HERMES-PRI/PCIX" } , + { 0x12AE, 0x0001, "3C986", "ACEnic 1000 BASE-SX Ethernet adapter" } , + { 0x12AE, 0x0002, "3C986-T", "Copper Gigabit Ethernet Adapter" } , + { 0x12BA, 0x0032, "Hammerhead-Lite-PCI", "DSP Prototyping & Development Card" } , + { 0x12C1, 0x9080, "Sync4hs/CCP/PCI/MP", "Communications Processor" } , + { 0x13A3, 0x0005, "7751", "Security Processor" } , + { 0x13A3, 0x0006, "6500", "Public Key Processor" } , + { 0x13A3, 0x0007, "7811", "Security Processor" } , + { 0x13A3, 0x0012, "7951", "Security Processor" } , + { 0x13A3, 0x0014, "7814/7851/7854", "Security Processor" } , + { 0x13A3, 0x0015, "8065", "Security Processor" } , + { 0x13A3, 0x0017, "8165", "Security Processor" } , + { 0x13A3, 0x0018, "8154", "Security Processor" } , + { 0x13A3, 0x001d, "7956", "Cryptographic Processor" } , + { 0x13A3, 0x0020, "7954/7955", "Cryptographic Processor" } , + { 0x13A3, 0x0016, "8065", "Security Processor" } , + { 0x12C3, 0x0058, "HT80232", "LAN Adapter (NE2000-compatible)" } , + { 0x12C3, 0x5598, "HT80229", "Ethernet Adapter (NE2000-compatible)" } , + { 0x12C4, 0x0001, "", "" } , + { 0x12C4, 0x0002, "", "" } , + { 0x12C4, 0x0003, "", "" } , + { 0x12C4, 0x0004, "", "" } , + { 0x12C4, 0x0005, "Blue Heat-8 RS232", "BlueHeat 8 Port RS232 Serial Board" } , + { 0x12C4, 0x0006, "", "" } , + { 0x12C4, 0x0007, "", "" } , + { 0x12C4, 0x0008, "", "" } , + { 0x12C4, 0x0009, "", "" } , + { 0x12C4, 0x000A, "", "" } , + { 0x12C4, 0x000B, "", "" } , + { 0x12C4, 0x000C, "", "" } , + { 0x12C4, 0x000D, "", "" } , + { 0x12C4, 0x000E, "", "" } , + { 0x12C4, 0x000F, "", "" } , + { 0x12C4, 0x0300, "", "" } , + { 0x12C4, 0x0301, "", "" } , + { 0x12C4, 0x0302, "", "" } , + { 0x12C4, 0x0303, "", "" } , + { 0x12C4, 0x0304, "", "" } , + { 0x12C4, 0x0305, "", "" } , + { 0x12C4, 0x0306, "", "" } , + { 0x12C4, 0x0307, "", "" } , + { 0x12C4, 0x0308, "", "" } , + { 0x12C4, 0x0309, "", "" } , + { 0x12C4, 0x030A, "", "" } , + { 0x12C4, 0x030B, "", "" } , + { 0x12C5, 0x007F, "ISE", "PEI Imaging Subsystem Engine" } , + { 0x12C5, 0x0081, "PCIVST", "PCI Thresholding Engine" } , + { 0x12C5, 0x0085, "", "Video Simulator/Sender" } , + { 0x12C5, 0x0086, "THR2", "Multi-scale Thresholder" } , + { 0x12C7, 0x0546, "kssjsjj", "D120JCT-LS Card" } , + { 0x12C7, 0x0561, "", "BRI/2 Type Card (Voice Driver)" } , + { 0x12C7, 0x0647, "", "D/240JCT-T1 Card" } , + { 0x12C7, 0x0648, "", "D/300JCT-E1 Card" } , + { 0x12C7, 0x0649, "", "D/300JCT-E1 Card" } , + { 0x12C7, 0x0651, "", "MSI PCI Card" } , + { 0x12C7, 0x0673, "", "BRI/160-PCI Card" } , + { 0x12C7, 0x0674, "", "BRI/120-PCI Card" } , + { 0x12C7, 0x0675, "", "BRI/80-PCI Card" } , + { 0x12C7, 0x0676, "", "D/41JCT Card" } , + { 0x12C7, 0x0685, "", "D/480JCT-2T1 Card" } , + { 0x12C7, 0x0687, "", "D/600JCT-2E1 (75 Ohm) Card" } , + { 0x12C7, 0x0689, "D/600JCT-2E1", "Dialogic 2E1 - JCT series" } , + { 0x12C7, 0x0707, "", "D/320JCT (Resource Only) Card" } , + { 0x12C7, 0x0708, "", "D/160JCT (Resource Only) Card" } , + { 0x12CB, 0x0027, "StudioCard", "" } , + { 0x12CB, 0x002D, "BX-12", "" } , + { 0x12CB, 0x002E, "SC-2000", "" } , + { 0x12CB, 0x002F, "LX-44", "" } , + { 0x12CB, 0x0030, "SC-22", "" } , + { 0x12CB, 0x0031, "BX-44", "" } , + { 0x12CB, 0x0032, "LX-24M", "20-bit 2-in, 4-out audio card w/MPEG-2" } , + { 0x12CB, 0x0033, "LX-22M", "" } , + { 0x12CB, 0x0034, "BX-8", "" } , + { 0x12CB, 0x0035, "BX-12e", "" } , + { 0x12D4, 0x0301, "EP1S", "SS7 Telecommunications Interface Adapter" } , + { 0x12D5, 0x1000, "MAP-CA", "Broadband Signal Processor" } , + { 0x12D5, 0x1002, "MAP-1000", "Digital Signal Processor" } , + { 0x1755, 0x0000, "Au1500", "Au1500 Processor" } , + { 0x12D8, 0x71E2, "PI7C7300", "3 Port PCI to PCI bridge" } , + { 0x12D8, 0x8150, "PI7C8150", "2-Port PCI to PCI Bridge" } , + { 0x12D8, 0x8152, "PI7C8152", "2-Port PCI-To-PCI Bridge" } , + { 0x12D8, 0xe130, "PI7C9X130", "PCI-X Bridge" } , + { 0x12DB, 0x0003, "", "FoxFire II" } , + { 0x12DE, 0x0200, "", "Cryptoswift 200" } , + { 0x12DF, 0x2102, "Infineon PEB 20534", "Communications Controller" } , + { 0x12DF, 0x8236, "Unknown", "PCI Controller" } , + { 0x12E0, 0x0010, "ST16C654", "Quad UART" } , + { 0x12E0, 0x0020, "ST16C654", "Quad UART" } , + { 0x12E0, 0x0030, "ST16C654", "Quad UART" } , + { 0x12E4, 0x1000, "TR1000 PRI", "PRI Controller" } , + { 0x12E4, 0x1140, "", "ISDN Controller" } , + { 0x12E4, 0xB005, "TR1000 BRI", "BRI Controller" } , + { 0x12E4, 0xB006, "TR1000 BRI", "BRI Controller" } , + { 0x12EB, 0x0001, "AU8820", "Vortex 1 Digital Audio Processor" } , + { 0x12EB, 0x0002, "AU8830A2", "Vortex 2 Audio Processor" } , + { 0x12EB, 0x0003, "312EB&REV3", "Aureal Soundcard" } , + { 0x12EC, 0x8139, "0xxxx", "0xxxx" } , + { 0x12F2, 0x1002, "215RAAGCGA11F", "Grapics Radeon X850" } , + { 0x12F2, 0x3059, "VT8237", "AC97 Enhanced Audio Controller - the 8251 controller is different" } , + { 0x12F8, 0x0002, "VideoMaker", "s3 trio" } , + { 0x1DE1, 0x0391, "TRM-S1040", "SCSI ASIC" } , + { 0x1DE1, 0x2020, "DC-390", "SCSI Controller" } , + { 0x1DE1, 0x690C, "DC-690C", "IDE Cache Controller" } , + { 0x1DE1, 0xDC29, "DC290M", "Bus Master IDE PCI 2 controllers" } , + { 0x3D3D, 0x0001, "GLint 300SX", "3D Accelerator" } , + { 0x3D3D, 0x0002, "GLint 500TX", "Sapphire 3D Accelerator" } , + { 0x3D3D, 0x0003, "GLint", "Delta Geometry processor" } , + { 0x3D3D, 0x0004, "3C0SX", "2D+3D Accelerator" } , + { 0x3D3D, 0x0005, "Permedia", "2D+3D Accelerator" } , + { 0x3D3D, 0x0006, "GLint MX", "3D Accelerator" } , + { 0x3D3D, 0x0007, "3D Extreme", "Permedia II 2D+3D Accelerator" } , + { 0x3D3D, 0x0008, "GLint Gamma G1", "" } , + { 0x3D3D, 0x0009, "Permedia2v", "2d+3d chipset, integrated ramdac" } , + { 0x3D3D, 0x000A, "Permedia 3", "" } , + { 0x3D3D, 0x000C, "Permedia 3", "" } , + { 0x3D3D, 0x000D, "GLINT R4", "3D Accelerator" } , + { 0x3D3D, 0x000E, "GLINT Gamma G2", "" } , + { 0x3D3D, 0x0030, "0x030000", "3Dlabs Wildcat Realizm 800" } , + { 0x3D3D, 0x0100, "Permedia II", "2D+3D Accelerator" } , + { 0x3D3D, 0x1004, "Permedia", "3D+3D Accelerator" } , + { 0x3D3D, 0x3D04, "Permedia", "2D+3D Accelerator" } , + { 0x3D3D, 0xFFFF, "GLint VGA", "" } , + { 0x4005, 0x0300, "3220", "PCI Audio Device" } , + { 0x4005, 0x0308, "3220", "PCI Audio Device + modem" } , + { 0x4005, 0x0309, "ALS300+", "PCI Input Controller" } , + { 0x4005, 0x1064, "ALG2064", "GUI Accelerator" } , + { 0x4005, 0x2064, "", "GUI Accelerator" } , + { 0x4005, 0x2128, "ALG2364A", "GUI Accelerator" } , + { 0x4005, 0x2301, "ALG2301", "GUI Accelerator" } , + { 0x4005, 0x2302, "ALG2302", "GUI Accelerator" } , + { 0x4005, 0x2303, "AVG2302", "GUI Accelerator" } , + { 0x4005, 0x2364, "ALG2364", "GUI Accelerator" } , + { 0x4005, 0x2464, "ALG2464", "GUI Accelerator" } , + { 0x4005, 0x2501, "ALG2564A/25128A", "GUI Accelerator" } , + { 0x4005, 0x4000, "ALS4000", "Audio Chipset" } , + { 0x5333, 0x0551, "86C551", "Plato/PX" } , + { 0x5333, 0x5333, "S3 86c765", "via" } , + { 0x5333, 0x5631, "86C325", "Virge 3D " } , + { 0x5333, 0x8800, "86C866", "Vision 866 GUI Accelerator" } , + { 0x5333, 0x8801, "86C964", "Vision 964 GUI Accelerator" } , + { 0x5333, 0x8810, "86C732-P", "S3 TRIO32 IACB2 86C732-P" } , + { 0x5333, 0x8811, "8622mcq04", "Trio 64/64V" } , + { 0x5333, 0x8812, "86CM65?", "Aurora 64V+" } , + { 0x5333, 0x8813, "86C764", "Trio 32/64 GUI Accelerator v3" } , + { 0x5333, 0x8814, "86C767", "Trio 64UV+" } , + { 0x5333, 0x8815, "86CM66", "Aurora128" } , + { 0x5333, 0x883D, "86C988", "ViRGE/VX 3D GUI Accelerator" } , + { 0x5333, 0x8870, "Fire GL", "" } , + { 0x5333, 0x8880, "86C868", "Vision 868 GUI Accelerator VRAM rev. 0" } , + { 0x5333, 0x8881, "86C868", "Vision 868 GUI Accelerator VRAM rev. 1" } , + { 0x5333, 0x8882, "86C868", "Vision 868 GUI Accelerator VRAM rev. 2" } , + { 0x5333, 0x8883, "86C868", "Vision 868 GUI Accelerator VRAM rev. 3" } , + { 0x5333, 0x88B0, "86C928", "Vision 928 GUI Accelerator VRAM rev. 0" } , + { 0x5333, 0x88B1, "86C928", "Vision 928 GUI Accelerator VRAM rev. 1" } , + { 0x5333, 0x88B2, "86C928", "Vision 928 GUI Accelerator VRAM rev. 2" } , + { 0x5333, 0x88B3, "86C928", "Vision 928 GUI Accelerator VRAM rev. 3" } , + { 0x5333, 0x88C0, "86C864", "Vision 864 GUI Accelerator DRAM rev. 0" } , + { 0x5333, 0x88C1, "86C864", "Vision 864 GUI Accelerator DRAM rev. 1" } , + { 0x5333, 0x88C2, "86C864", "Vision 864 GUI Accelerator DRAM rev. 2" } , + { 0x5333, 0x88C3, "86C864", "Vision 864 GUI Accelerator DRAM rev. 3" } , + { 0x5333, 0x88D0, "86C964", "Vision 964 GUI Accelerator VRAM rev. 0" } , + { 0x5333, 0x88D1, "86C964", "Vision 964-P GUI Accelerator VRAM rev. 1" } , + { 0x5333, 0x88D2, "86C964", "Vision 964-P GUI Accelerator DRAM rev 2" } , + { 0x5333, 0x88D3, "86C964", "Vision 964-P GUI Accelerator VRAM rev. 3" } , + { 0x5333, 0x88F0, "86C968", "Vision 968 GUI Accelerator VRAM rev. 0" } , + { 0x5333, 0x88F1, "86C968", "Vision 968 GUI Accelerator VRAM rev. 1" } , + { 0x5333, 0x88F2, "86C968", "Vision 968 GUI Accelerator VRAM rev. 2" } , + { 0x5333, 0x88F3, "86C968", "Vision 968 GUI Accelerator VRAM rev. 3" } , + { 0x5333, 0x8900, "86C775", "Trio64V2/DX" } , + { 0x5333, 0x8901, "pci\ven_5333dev_8C2E&SUBSYS_00011179&REV_05\4&74C6", "S3 trio64uv+ for windows xp" } , + { 0x5333, 0x8902, "86C551", "SMA Family" } , + { 0x5333, 0x8903, "", "TrioV Family" } , + { 0x5333, 0x8904, "86C365/366", "Trio3D QFP/BGA" } , + { 0x5333, 0x8905, "86c765", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x8906, "86c765", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x8907, "86c765", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x8908, "9711 MCN74", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x8909, "7699688", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x890A, "0x00091011", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x890B, "9726 c19394.00", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x890C, "86C765", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x890D, "", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x890E, "9711 MCN74", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x890F, "86c765", "86C765 Trio64V+ compatible" } , + { 0x5333, 0x8A01, "86C375/86C385", "ViRGE /DX & /GX" } , + { 0x5333, 0x8A10, "86C357", "ViRGE /GX2" } , + { 0x5333, 0x8A11, "86C359", "ViRGE /GX2+ Macrovision" } , + { 0x5333, 0x8A12, "86C359", "ViRGE /GX2+" } , + { 0x5333, 0x8A13, "86C368", "Trio3D2x & Trio3D2x+ AGP / Trio3D2x & Trio3D2x+ 8MB" } , + { 0x5333, 0x8A20, "86C391", "S3savage3D" } , + { 0x5333, 0x8A21, "86C390", "Savage3D/MV" } , + { 0x5333, 0x8A22, "86c398", "Savage 4" } , + { 0x5333, 0x8A23, "86C394-397", "Savage 4" } , + { 0x5333, 0x8A25, "86C370", "Savage4" } , + { 0x5333, 0x8A26, "86C395B", "ProSavage" } , + { 0x5333, 0x8C00, "85C260", "ViRGE/M3 (ViRGE/MX)" } , + { 0x5333, 0x8C01, "86C260", "ViRGE/M5 (ViRGE/MX)" } , + { 0x5333, 0x8C02, "86C240", "ViRGE/MXC" } , + { 0x5333, 0x8C03, "86C280 db", "ViRGE /MX+mv" } , + { 0x5333, 0x8C10, "86C270/274/290/294", "Savage MX/IX/MX+MV/IX+MV" } , + { 0x5333, 0x8C12, "86C270/274/290/294", "Savage MX/IX/MX+MV/IX+MV" } , + { 0x5333, 0x8C13, "82C294", "SAVAGE IX" } , + { 0x5333, 0x8C22, "86C508", "SuperSavage 128/MX" } , + { 0x5333, 0x8C2A, "86C544", "SuperSavage 128/IX" } , + { 0x5333, 0x8C2B, "86C553", "SuperSavage 128/IX DDR" } , + { 0x5333, 0x8C2C, "86C564", "SuperSavage/IX" } , + { 0x5333, 0x8C2D, "86C573", "SuperSavage/IX DDR" } , + { 0x5333, 0x8C2E, "86C584", "SuperSavage/IXC SDRAM" } , + { 0x5333, 0x8C2F, "86C594", "SuperSavage/IXC DDR" } , + { 0x5333, 0x8D01, "86C380/381", "Twister/Twister T" } , + { 0x5333, 0x8D02, "86c387", "Twister K" } , + { 0x5333, 0x8D04, "86C410", "ProSavage DDR" } , + { 0x5333, 0x8E00, "86C777/787", "DeltaChrome S8/F1" } , + { 0x5333, 0x8E01, "86C732", "DeltaChromeX9m" } , + { 0x5333, 0x9102, "86c410", "Inno Savage 2000" } , + { 0x5333, 0xCA00, "86C617", "SonicVibes PCI Audio Accelerator" } , + { 0x165F, 0x2000, "XILINX SPARTAN", "16 Channel Audio Capture Card" } , + { 0x8086, 0x0008, "", "Extended Express System Support Ctrlr" } , + { 0x8086, 0x283E, "AA", "Intel(R) ICH8 Family SMBus Controller" } , + { 0x8086, 0x0309, "80303", "I/O Processor PCI-to-PCI Bridge Unit" } , + { 0x8086, 0x030D, "80312", "I/O Companion Unit PCI-to-PCI Bridge" } , + { 0x8086, 0x0318, "80219", "General Purpose PCI Processor Address Translation Unit" } , + { 0x8086, 0x0319, "80219", "General Purpose PCI Processor Address Translation Unit" } , + { 0x8086, 0x0326, "670xPXH", "I/OxAPIC Interrupt Controller" } , + { 0x8086, 0x0327, "6700PXH", "I/OxAPIC Interrupt Controller B" } , + { 0x8086, 0x0329, "6700PXH", "PCI Express-to-PCI Express Bridge A" } , + { 0x8086, 0x032A, "6700PXH", "PCI Express-to-PCI Express Bridge B" } , + { 0x8086, 0x032C, "6702PXH", "PCI Express-to-PCI Express Bridge" } , + { 0x8086, 0x0330, "80332", "A-Segment Bridge" } , + { 0x8086, 0x0331, "80332", "A-Segment IOAPIC" } , + { 0x8086, 0x0332, "80332", "B-Segment Bridge" } , + { 0x8086, 0x0333, "80332", "B-Segment IOAPIC" } , + { 0x8086, 0x0334, "80332", "Address Translation Unit" } , + { 0x8086, 0x0335, "80331", "PCI-X Bridge" } , + { 0x8086, 0x0336, "80331", "Address Translation Unit (ATU)" } , + { 0x8086, 0x0340, "41210", "Serial to Parallel PCI Bridge A" } , + { 0x8086, 0x0341, "41210", "Serial to Parallel PCI Bridge B" } , + { 0x8086, 0x0370, "80333", "Segment-A PCI Express-to-PCI Express Bridge" } , + { 0x8086, 0x0371, "80333", "A-Bus IOAPIC" } , + { 0x8086, 0x0372, "80333", "Segment-B PCI Express-to-PCI Express Bridge" } , + { 0x8086, 0x0373, "80333", "B-Bus IOAPIC" } , + { 0x8086, 0x0374, "80333", "Address Translation Unit" } , + { 0x8086, 0x0482, "82375MB", "PCI-EISA Bridge (PCEB)" } , + { 0x8086, 0x0483, "82424TX/ZX", "CPU (i486) Bridge (Saturn)" } , + { 0x8086, 0x0484, "82378ZB/IB", "SIO ISA Bridge" } , + { 0x8086, 0x0486, "82425EX", "" } , + { 0x8086, 0x04A3, "82434bX/zX", "Mercury/Neptune Cache/DRAM Controller" } , + { 0x8086, 0x0500, "E8870", "Processor Bus Controller" } , + { 0x8086, 0x0501, "E8870", "Memory Controller" } , + { 0x8086, 0x0502, "E8870", "Scalability Port 0" } , + { 0x8086, 0x0503, "E8870", "Scalability Port 1 / Glob. Perf. Monitor" } , + { 0x8086, 0x0510, "E8870IO", "Hub Interface Port 0 (8-bit compatible)" } , + { 0x8086, 0x0511, "E8870IO", "Hub Interface Port 1" } , + { 0x8086, 0x0512, "E8870IO", "Hub Interface Port 2" } , + { 0x8086, 0x0513, "E8870IO", "Hub Interface Port 3" } , + { 0x8086, 0x0514, "E8870IO", "Hub Interface Port 4" } , + { 0x8086, 0x0515, "E8870IO", "Server I/O Hub (SIOH)" } , + { 0x8086, 0x0516, "E8870IO", "Reliabilty, Availability, Serviceability" } , + { 0x8086, 0x0530, "E8870SP", "Scalability Port 0" } , + { 0x8086, 0x0531, "E8870SP", "Scalability Port 1" } , + { 0x8086, 0x0532, "E8870SP", "Scalability Port 2" } , + { 0x8086, 0x0533, "E8870SP", "Scalability Port 3" } , + { 0x8086, 0x0534, "E8870SP", "Scalability Port 4" } , + { 0x8086, 0x0535, "E8870SP", "Scalability Port 5" } , + { 0x8086, 0x0536, "E8870SP", "Scalability Port Switch Global Registers" } , + { 0x8086, 0x0537, "E8870SP", "Interleave Configuration Registers" } , + { 0x8086, 0x0600, "01af8086", "Storage RAID Controller" } , + { 0x8086, 0x0960, "80960RP", "i960 RP Microprocessor/Bridge" } , + { 0x8086, 0x0962, "80960RM/RN", "i960RM/RN Microprocessor/Bridge" } , + { 0x8086, 0x0964, "80960RP", "i960 RP Microprocessor Bridge" } , + { 0x8086, 0x1000, "82542", "Gigabit Ethernet Controller" } , + { 0x8086, 0x1001, "2572", "10/100/1000 Ethernet Controller (Fiber)" } , + { 0x8086, 0x1002, "", "Pro 100 LAN+Modem 56 CardBus II" } , + { 0x8086, 0x1004, "82543GC", "Gigabit Ethernet Controller (Copper)" } , + { 0x8086, 0x1008, "82544EI/GC", "Gigabit Ethernet Controller (Copper)" } , + { 0x8086, 0x1009, "82544EI", "Gigabit Ethernet Controller (Fiber)" } , + { 0x8086, 0x100C, "82543EI/GC", "Gigabit Ethernet Controller (Copper)" } , + { 0x8086, 0x100D, "82544GC", "Gigabit Ethernet Controller (LOM)" } , + { 0x8086, 0x100E, "82540EM", "Gigabit Ethernet Controller" } , + { 0x8086, 0x100F, "82545EM", "Gigabit Ethernet Controller (copper)" } , + { 0x8086, 0x1010, "82546EB", "Dual Port Gigabit Ethernet Controller (Copper)" } , + { 0x8086, 0x1011, "82545EM", "Gigabit Ethernet Controller (Fiber)" } , + { 0x8086, 0x1012, "82546EB", "Dual Port Gigabit Ethernet Controller (Fiber)" } , + { 0x8086, 0x1013, "82541EI", "Gigabit Ethernet Controller (Copper)" } , + { 0x8086, 0x1014, "82541ER", "Gigabit Ethernet Controller" } , + { 0x8086, 0x1015, "82540EM", "Gigabit Ethernet Controller (LOM)" } , + { 0x8086, 0x1016, "82540EP", "Gigabit Ethernet Controller (LOM)" } , + { 0x8086, 0x1017, "82540EP", "Gigabit Ethernet Controller (LOM)" } , + { 0x8086, 0x1018, "82541EI", "PRO/1000 MT Mobile connection" } , + { 0x8086, 0x1019, "82547EI", "Gigabit Ethernet Controller (LOM)" } , + { 0x8086, 0x101A, "82547EI", "Gigabit Ethernet Controller (LOM)" } , + { 0x8086, 0x101d, "82546EB", "Dual Port Gigabit Ethernet Controller" } , + { 0x8086, 0x101E, "82540EP", "Gigabit Ethernet Controller (Mobile)" } , + { 0x8086, 0x1026, "82545ep", "Gigabit Ethernet Controller" } , + { 0x8086, 0x1027, "82545GM", "Gigabit Ethernet Controller (Fiber)" } , + { 0x8086, 0x1028, "82545GM", "Gigabit Ethernet Controller" } , + { 0x8086, 0x1029, "82559", "Fast Ethernet PCI/CardBus Controller" } , + { 0x8086, 0x1030, "825593", "PCI Networking device" } , + { 0x8086, 0x1031, "82801CAM", "PRO/100 VE Network Connection" } , + { 0x8086, 0x1032, "82801CAM", "PRO/100 VE Network Connection" } , + { 0x8086, 0x1033, "82801CAM", "PRO/100 VM Network Connection" } , + { 0x8086, 0x1034, "82801CAM", "PRO/100 VM Network Connection" } , + { 0x8086, 0x1035, "82562EH", "Phoneline Network Connection" } , + { 0x8086, 0x1036, "82562EH", "Phoneline Network Connection" } , + { 0x8086, 0x1037, "82801CAM", "LAN Controller" } , + { 0x8086, 0x1038, "82801CAM", "PRO/100 VM/KM Network Connection" } , + { 0x8086, 0x1039, "10011734", "LAN Controller with 82562ET/EZ PHY" } , + { 0x8086, 0x103A, "82801DB", "LAN Controller with 82562ET/EZ (CNR) PHY" } , + { 0x8086, 0x103B, "82801DB", "LAN Controller with 82562EM/EX PHY" } , + { 0x8086, 0x103C, "82801DB", "LAN Controller with 82562EM/EX (CNR) PHY" } , + { 0x8086, 0x103D, "82801DB", "PRO/100 VE Network Connection" } , + { 0x8086, 0x103E, "82801DB", "PRO/100 VM Network Connection" } , + { 0x8086, 0x1040, "536EP", "V.92 PCI (DSP) Data Fax Modem" } , + { 0x8086, 0x1042, "", "PRO/Wireless 2011 LAN PCI Card" } , + { 0x8086, 0x1043, "82801", "Intel(R) PRO/Wireless 2100 LAN Card Driver" } , + { 0x8086, 0x1048, "82597EX", "10 Gigabit Ethernet Controller" } , + { 0x8086, 0x1049, "82566MM NIC", "Gigabit Network Connection Interface Controller" } , + { 0x8086, 0x104A, "82566DM", "Gigabit Ethernet" } , + { 0x8086, 0x104B, "82566DC", "Gigabit Ethernet" } , + { 0x8086, 0x1050, "82801EB/ER", "PRO/100 VE Network Connection" } , + { 0x8086, 0x1051, "82801EB/ER", "PRO/100 VE Network Connection" } , + { 0x8086, 0x1052, "82801EB/ER", "PRO/100 VM Network Connection" } , + { 0x8086, 0x1053, "82801EB/ER", "PRO/100 VM Network Connection" } , + { 0x8086, 0x1054, "82801EB/ER", "PRO/100 VE Network Connection (mobile)" } , + { 0x8086, 0x1055, "82801EB/ER", "PRO/100 VM Network Connection (mobile)" } , + { 0x8086, 0x1059, "82551QM", "Fast Ethernet PCI/CardBus Controller" } , + { 0x8086, 0x105E, "n1e5132", "HP NC360T PCIe DP Gigabit Server Adapter" } , + { 0x8086, 0x1064, "Intel Pro VE", "82562EZ PLC" } , + { 0x8086, 0x1065, "82801FB/FR/FW/FRW", "LAN Controller" } , + { 0x8086, 0x1068, "82562", "1068h 82562ET/EZ/GT/GZ PRO/100 VE Ethernet Controller" } , + { 0x8086, 0x1075, "82547EI", "Gigabit Ethernet Controller" } , + { 0x8086, 0x1076, "82541EI", "Gigabit Ethernet Controller" } , + { 0x8086, 0x1077, "82547EI", "Gigabit Ethernet Controller (Mobile)" } , + { 0x8086, 0x1078, "82541ER", "Gigabit Ethernet Controller" } , + { 0x8086, 0x1079, "82546EB", "Dual Port Gigabit Ethernet Controller" } , + { 0x8086, 0x107A, "82546EB", "Dual Port Gigabit Ethernet Controller (Fiber)" } , + { 0x8086, 0x107B, "82546EB", "Dual Port Gigabit Ethernet Controller (Copper)" } , + { 0x8086, 0x107C, "82541PI", "Gigabit Ethernet Controller (Copper) rev 5" } , + { 0x8086, 0x1080, "0321CGEA04", "FA82537EP - Intel 537EP V.92 (PCI) modem" } , + { 0x8086, 0x108B, "PC82573V", "Intel network controller (PCIE Gigabit Ethernet)" } , + { 0x8086, 0x108c, "82573E", "Intel Corporation 82573E Gigabit Ethernet Controller (Copper)" } , + { 0x8086, 0x108E, "ICH7R", "Intel(R) Active Management Technology - KCS" } , + { 0x8086, 0x108F, "ICH7R", "Intel(R) Active Management Technology - SOL" } , + { 0x8086, 0x1092, "27DA", "PRO/100 VE Network Controller" } , + { 0x8086, 0x1094, "Onboard - Intel PRO 100/VE nic", "get PRO2KXP.exe from Intel" } , + { 0x8086, 0x1096, "Intel PRO/1000 EB", "Intel PRO/1000 EB" } , + { 0x8086, 0x109A, "82573L", "Intel PRO/1000 PL Network Adaptor" } , + { 0x8086, 0x10b9, "82572GI", "Intel PRO/1000 PT Desktop" } , + { 0x8086, 0x10BD, "82566DM", "Intel 82566DM Gigabit Ethernet Adapter" } , + { 0x8086, 0x10C0, "8082", "Intel(R) 82562V-2 10/100 Network Connection" } , + { 0x8086, 0x10DE, "83567LM-3 ", "Intel Gigabit network connection" } , + { 0x8086, 0x10F5, "82567LM", "Intel� 82567LM-2 Gigabit Network Connection" } , + { 0x8086, 0x1100, "82815/EP/P", "Host-Hub Interface Bridge / DRAM Ctrlr" } , + { 0x8086, 0x1101, "82815/EP/P", "AGP Bridge" } , + { 0x8086, 0x1102, "82815", "Internal Graphics Device" } , + { 0x8086, 0x1110, "82815", "Host-Hub Interface Bridge / DRAM Ctrlr" } , + { 0x8086, 0x1112, "82815", "Internal Graphics Device" } , + { 0x8086, 0x1120, "82815", "Host-Hub Interface Bridge / DRAM Ctrlr" } , + { 0x8086, 0x1121, "82815", "AGP Bridge" } , + { 0x8086, 0x1130, "82815/82815EM/EP", "Host-Hub Interface Bridge / DRAM Ctrlr" } , + { 0x8086, 0x1131, "82815/82815EM/EP", "AGP Bridge" } , + { 0x8086, 0x1132, "65416", "Internal Graphics Device [810/815 chipset AGP]" } , + { 0x8086, 0x1161, "82806AA", "I/O APIC Device" } , + { 0x8086, 0x1162, "BECC", "XScale 80200 Companion Chip (FPGA)" } , + { 0x8086, 0x1179, "82546EB", "Dual Port Gigabit Ethernet Controller" } , + { 0x8086, 0x1200, "IXP1200", "Network Processor" } , + { 0x8086, 0x1209, "8255xER/IT", "Fast Ethernet Controller" } , + { 0x8086, 0x1221, "82092AA", "PCMCIA Bridge" } , + { 0x8086, 0x1222, "82092AA", "IDE Ctrlr" } , + { 0x8086, 0x1223, "SAA 7116 H", "Video Controller" } , + { 0x8086, 0x1225, "82452KX/GX", "Orion Extended Express CPU to PCI Bridge" } , + { 0x8086, 0x1226, "82596", "EtherExpress PRO/10" } , + { 0x8086, 0x1227, "82801db ich4", "LAN Controller with 82562EM/EX PHY PCI" } , + { 0x8086, 0x1228, "EE PRO/100 Smart", "Intelligent 10/100 Fast Ethernet Adapter" } , + { 0x8086, 0x1229, "82557/8/9/0/1", "Fast Ethernet LAN Controller" } , + { 0x8086, 0x122D, "82437FX", "System Controller (TSC)" } , + { 0x8086, 0x122E, "82371FB", "PCI to ISA Bridge (Triton)" } , + { 0x8086, 0x1230, "FW82371AB", "IDE Interface (Triton)" } , + { 0x8086, 0x1231, "16345", "DSVD Modem" } , + { 0x8086, 0x1234, "82371MX", "PCI to ISA Bridge" } , + { 0x8086, 0x1235, "82439TX", "Mobile System Controller (MTSC)" } , + { 0x8086, 0x1237, "82440LX/EX", "PCI & Memory" } , + { 0x8086, 0x1239, "82371FB", "IDE Interface (Triton)" } , + { 0x8086, 0x123B, "82380PB", "PCI to PCI Docking Bridge" } , + { 0x8086, 0x123C, "82380AB", "Mobile PCI-to-ISA Bridge (MISA)" } , + { 0x8086, 0x123D, "683053", "Programmable Interrupt Device" } , + { 0x8086, 0x123E, "82466GX", "Integrated Hot-Plug Controller (IHPC)" } , + { 0x8086, 0x123F, "82466GX", "Integrated Hot-Plug Controller (IHPC)" } , + { 0x8086, 0x1240, "82752", "AGP Graphics Accelerator" } , + { 0x8086, 0x124B, "4227", "Mobile PCI-to-PCI Bridge (MPCI2)" } , + { 0x8086, 0x1250, "82430HX", "System Controller (TXC)" } , + { 0x8086, 0x12D8, "92XX", "SIGMATEL STAC 92XX C-Major HD Audio" } , + { 0x8086, 0x1360, "82806AA", "Hub Interface to PCI Bridge" } , + { 0x8086, 0x1361, "82806AA", "Advanced Interrupt Controller" } , + { 0x8086, 0x1460, "82870P2", "Hub Interface-to-PCI Bridge" } , + { 0x8086, 0x1461, "14611014", "I/OxAPIC Interrupt Controller" } , + { 0x8086, 0x1462, "82870P2", "Hot Plug Controller" } , + { 0x8086, 0x1960, "80960RP", "i960RP Microprocessor" } , + { 0x8086, 0x1962, "???", "Promise SuperTrak SX6000 IDE RAID Controller" } , + { 0x8086, 0x1A12, "???", "Eicon DIVA Server Voice PRI 2.0 (PCI)" } , + { 0x8086, 0x1A13, "???", "Eicon DIVA Server Voice PRI 2.0 (PCI)" } , + { 0x8086, 0x1A20, "82840", "" } , + { 0x8086, 0x1A21, "82840", "Host-Hub Interface A Bridge / DRAM Ctrlr" } , + { 0x8086, 0x1A22, "82840", "Host to I/O Hub Bridge (Quad PCI)" } , + { 0x8086, 0x1A23, "82840", "AGP Bridge" } , + { 0x8086, 0x1A24, "82840", "Hub Interface B Bridge" } , + { 0x8086, 0x1A30, "82845G[GL/GV/GE/PE]", "Host-Hub Interface Bridge" } , + { 0x8086, 0x1A31, "82845[MP/MZ]", "AGP Bridge" } , + { 0x8086, 0x1A38, "5000P", "5000 Series Chipset DMA Engine" } , + { 0x8086, 0x2125, "82801AA", "AC97 Audio Controller. website to download - http://www.intel.com/design/chipsets/manuals/29802801.p" } , + { 0x8086, 0x2410, "82801AA", "LPC Interface" } , + { 0x8086, 0x2411, "82801AA", "IDE Controller (UltraATA/66)" } , + { 0x8086, 0x2412, "82801AA", "USB Controller" } , + { 0x8086, 0x2413, "82801AA", "SMBus Controller" } , + { 0x8086, 0x2415, "Intel 82801DBM SM/BUS Controller 24C3", "Aureal (AD1881 SOUNDMAX) Placa Mãe Asaki P3-141" } , + { 0x8086, 0x2416, "82801fb", "AC'97 Modem Controller" } , + { 0x8086, 0x2418, "82801AA", "Hub Interface-to-PCI Bridge" } , + { 0x8086, 0x2420, "82801AB", "LPC Interface" } , + { 0x8086, 0x2421, "82801AB", "IDE Controller (UltraATA/33)" } , + { 0x8086, 0x2422, "82801AB", "USB Controller" } , + { 0x8086, 0x2423, "82801AB", "SMBus Controller" } , + { 0x8086, 0x2425, "82845G", "Video controler" } , + { 0x8086, 0x2426, "82801AB", "AC97 Modem Controller" } , + { 0x8086, 0x2428, "82801AB", "Hub Interface-to-PCI Bridge" } , + { 0x8086, 0x2431, "82810", "pci bus" } , + { 0x8086, 0x2440, "82801BA", "LPC Interface Bridge, ICH2" } , + { 0x8086, 0x2441, "82801BA", "IDE Controller (UltraATA/66)" } , + { 0x8086, 0x2442, "82801BA/BAM", "USB Controller, USB-A" } , + { 0x8086, 0x2443, "0055110A", "SMBus Controller" } , + { 0x8086, 0x2444, "82801BA/BAM", "USB Controller, USB-B" } , + { 0x8086, 0x2445, "Intel i945G/GZ", "AC97 Audio Controller" } , + { 0x8086, 0x2446, "82801BA/BAM", "AC97 Modem Controller" } , + { 0x8086, 0x2448, "82801BAM/CAM/DBM", "Hub Interface to PCI Bridge" } , + { 0x8086, 0x2449, "82559ER", "82559ER Integrated 10Base-T/100Base-TX Ethernet Controller" } , + { 0x8086, 0x244A, "82801BAM", "IDE Controller" } , + { 0x8086, 0x244B, "82801BA", "IDE Controller" } , + { 0x8086, 0x244C, "82801BAM", "LPC Interface Bridge" } , + { 0x8086, 0x244E, "82801DB", "Hub Interface to PCI Bridge" } , + { 0x8086, 0x2450, "82801E", "LPC Interface Bridge" } , + { 0x8086, 0x2452, "82801E", "USB Controller" } , + { 0x8086, 0x2453, "82801E", "SMBus Controller" } , + { 0x8086, 0x2459, "82801E", "LAN0 Controller" } , + { 0x8086, 0x245B, "82801E", "IDE Controller" } , + { 0x8086, 0x245D, "82801E", "LAN1 Controller" } , + { 0x8086, 0x245E, "82801E", "Hub Interface to PCI Bridge" } , + { 0x8086, 0x2480, "82801CA", "LPC Interface Bridge" } , + { 0x8086, 0x2481, "82801CA", "IDE Controller (UltraATA/66)" } , + { 0x8086, 0x2482, "82801CA/CAM", "USB Controller" } , + { 0x8086, 0x2483, "82801CA/CAM", "SMBus Controller" } , + { 0x8086, 0x2484, "82801CA/CAM", "USB Controller" } , + { 0x8086, 0x2485, "82801CA/CAM", "AC97 Audio Controller" } , + { 0x8086, 0x2486, "82801CA/CAM", "AC 97 Modem Controller" } , + { 0x8086, 0x2487, "82801CA/CAM", "USB Controller" } , + { 0x8086, 0x248A, "82801CAM", "UltraATA IDE Controller" } , + { 0x8086, 0x248B, "82801CA", "UltraATA/100 IDE Controller" } , + { 0x8086, 0x248C, "82801CAM", "LPC Interface or ISA bridge: see Notes" } , + { 0x8086, 0x248D, "82801??", "USB 2.0 EHCI Contoroller" } , + { 0x8086, 0x24C0, "82801DB/DBL", "LPC Interface Bridge" } , + { 0x8086, 0x24C2, "82801DB/DBL/DBM", "USB UHCI Controller #1" } , + { 0x8086, 0x24C3, "82801DB/DBL/DBM", "modem" } , + { 0x8086, 0x24C4, "82801DB/DBL/DBM", "USB UHCI Controller" } , + { 0x8086, 0x24C5, "Realtek ALC268 & ALC650", "RealTek" } , + { 0x8086, 0x24C5, "Subsys_01601028", "Soundmax Integrated Digital Audio" } , + { 0x8086, 0x24C6, "82801", "AC97 Modem Controller" } , + { 0x8086, 0x24C7, "82801DB/DBL/DBM", "USB UHCI Controller #3" } , + { 0x8086, 0x24CA, "82801DBM", "IDE Controller (UltraATA/100)" } , + { 0x8086, 0x24CB, "82801DB/DBL", "IDE Controller (UltraATA/100)" } , + { 0x8086, 0x24CC, "82801DBM", "LPC Interface Bridge" } , + { 0x8086, 0x24CD, "82801DB/DBL/DBM", "USB EHCI Controller" } , + { 0x8086, 0x24D0, "82801EB/ER", "LPC Interface Bridge" } , + { 0x8086, 0x24D1, "82801EB/ER", "SATA Controller" } , + { 0x8086, 0x24D2, "82801EB/ER", "USB UHCI Controller #1" } , + { 0x8086, 0x24D3, "82801EB/ER", "SMBus Controller" } , + { 0x8086, 0x24D4, "82801EB/ER", "USB UHCI Controller #2" } , + { 0x8086, 0x24D5, "815B104D", "multimedia audio device (codec AC97) SoundMAX or VIA" } , + { 0x8086, 0x24D6, "82801EB/ER", "AC'97 Modem Controller" } , + { 0x8086, 0x24D7, "82801EB/ER", "USB UHCI Controller #3" } , + { 0x8086, 0x24DB, "82801EB/ER", "EIDE Controller" } , + { 0x8086, 0x24DC, "82801EB", "LPC Interface Controller" } , + { 0x8086, 0x24DD, "82801EB/ER", "USB EHCI Controller" } , + { 0x8086, 0x24DE, "82801EB/ER", "USB UHCI Controller #4" } , + { 0x8086, 0x24DF, "82801ER", "SATA Controller (RAID)" } , + { 0x8086, 0x2500, "82820", "Host-Hub Interface Bridge / DRAM Ctrlr" } , + { 0x8086, 0x2501, "82820", "Host Bridge (MCH)" } , + { 0x8086, 0x2502, "82820", "" } , + { 0x8086, 0x2503, "82820", "" } , + { 0x8086, 0x2504, "82820", "" } , + { 0x8086, 0x250B, "82820", "Host Bridge (MCH)" } , + { 0x8086, 0x250F, "82820", "AGP Bridge" } , + { 0x8086, 0x2520, "82805AA", "Memory Translator Hub (MTH)" } , + { 0x8086, 0x2521, "82804AA", "Memory Repeater Hub for SDRAM (MRH-S)" } , + { 0x8086, 0x2530, "82850/E", "Host-Hub Interface Bridge(A2 step)" } , + { 0x8086, 0x2531, "82860", "Host-Hub Interface_A Bridge (DP mode)" } , + { 0x8086, 0x2532, "82850/850E/860", "AGP Bridge" } , + { 0x8086, 0x2533, "82860", "Hub Interface_B Bridge" } , + { 0x8086, 0x2534, "82860", "Hub Interface_C Bridge" } , + { 0x8086, 0x2535, "82860", "PCI Bridge" } , + { 0x8086, 0x2536, "82860", "PCI Bridge" } , + { 0x8086, 0x2539, "82860", "(Quad Processor mode)" } , + { 0x8086, 0x2540, "E7500", "Host-HI Bridge & DRAM Controller" } , + { 0x8086, 0x2541, "E7500/E7501", "DRAM Controller Error Reporting" } , + { 0x8086, 0x2543, "E7500/E7501", "HI_B Virtual PCI-to-PCI Bridge" } , + { 0x8086, 0x2544, "E7500/E7501", "HI_B PCI-to-PCI Bridge Error Reporting" } , + { 0x8086, 0x2545, "E7500/E7501", "HI_C Virtual PCI-to-PCI Bridge" } , + { 0x8086, 0x2546, "E7500/E7501", "HI_C PCI-to-PCI Bridge Error Reporting" } , + { 0x8086, 0x2547, "E7500/E7501", "HI_D Virtual PCI-to-PCI Bridge" } , + { 0x8086, 0x2548, "E7500/E7501", "HI_D PCI-to-PCI Bridge Error Reporting" } , + { 0x8086, 0x254C, "E7501", "Host Controller" } , + { 0x8086, 0x2550, "E7505", "Host Controller" } , + { 0x8086, 0x2551, "25511014", "Host RAS Controller" } , + { 0x8086, 0x2552, "E7205/E7505", "PCI-to-AGP Bridge" } , + { 0x8086, 0x2553, "E7505", "Hub Interface_B PCI-to-PCI Bridge" } , + { 0x8086, 0x2554, "E7505", "Hub I/F_B PCI-to-PCI Bridge Error Report" } , + { 0x8086, 0x255d, "E7205", "Host Controller" } , + { 0x8086, 0x2560, "82845G/GL/GV/GE/PE", "DRAM Controller / Host-Hub I/F Bridge" } , + { 0x8086, 0x2561, "82845G/GL/GV/GE/PE", "Host-to-AGP Bridge" } , + { 0x8086, 0x2562, "82845G", "Integrated Graphics Device" } , + { 0x8086, 0x2570, "82865G/PE/P, 82848P", "DRAM Controller / Host-Hub Interface" } , + { 0x8086, 0x2571, "82865G/PE/P, 82848P", "PCI-to-AGP Bridge" } , + { 0x8086, 0x2572, "82865G", "Integrated Graphics Device" } , + { 0x8086, 0x2573, "82865G/PE/P, 82848P", "PCI-to-CSA Bridge" } , + { 0x8086, 0x2576, "82865G/PE/P, 82848P", "Overflow Configuration" } , + { 0x8086, 0x2578, "82875P/E7210", "DRAM Controller / Host-Hub Interface" } , + { 0x8086, 0x2579, "82875P", "PCI-to-AGP Bridge" } , + { 0x8086, 0x257A, "", "" } , + { 0x8086, 0x257B, "82875P/E7210", "PCI to CSA Bridge" } , + { 0x8086, 0x257E, "82875P/E7210", "Overflow Configuration" } , + { 0x8086, 0x2580, "915G/P/GV", "Host Bridge / DRAM Controller" } , + { 0x8086, 0x2581, "915G/P/GV, 925X/XE?", "Host-PCI Express Bridge" } , + { 0x8086, 0x2582, "0181102", "82915g/gv/910gl Express Chipset Family" } , + { 0x8086, 0x2584, "82925X/XE", "Host Bridge / DRAM Controller" } , + { 0x8086, 0x2588, "E7221", "Host Bridge/DRAM Controller" } , + { 0x8086, 0x2589, "E7221", "PCI Express Bridge" } , + { 0x8086, 0x258A, "E7221", "Internal Graphics" } , + { 0x8086, 0x2590, "915GM", "Mobile Intel(R) 915GM/PM/GMS/910GML Express Processor to DRAM Controller" } , + { 0x8086, 0x2592, "Intel 82852/82855 Graphic controller family", "you can be found in www.intelcom" } , + { 0x8086, 0x25A1, "6300ESB", "LPC Interface Bridge" } , + { 0x8086, 0x25A2, "6300ESB", "IDE Controller" } , + { 0x8086, 0x25A3, "6300ESB", "SATA Controller" } , + { 0x8086, 0x25A4, "6300ESB", "SMBus Controller" } , + { 0x8086, 0x25A6, "6300ESB", "AC'97 Audio Controller" } , + { 0x8086, 0x25A7, "6300ESB", "AC'97 Modem Controller" } , + { 0x8086, 0x25A9, "6300ESB", "USB 1.1 UHCI Controller #1" } , + { 0x8086, 0x25AA, "6300ESB", "USB 1.1 UHCI Controller #2" } , + { 0x8086, 0x25AB, "6300ESB", "Watchdog Timer" } , + { 0x8086, 0x25AC, "6300ESB", "APIC1" } , + { 0x8086, 0x25AD, "6300ESB", "USB 2.0 EHCI Controller" } , + { 0x8086, 0x25AE, "6300ESB", "Hub Interface to PCI-X Bridge" } , + { 0x8086, 0x25B0, "6300ESB", "Serial ATA Controller (RAID mode)" } , + { 0x8086, 0x2600, "E8500", "Hub Interface 1.5" } , + { 0x8086, 0x2601, "E8500", "PCI Express Port D" } , + { 0x8086, 0x2602, "E8500", "PCI Express Port C0" } , + { 0x8086, 0x2603, "E8500", "PCI Express Port C1" } , + { 0x8086, 0x2604, "E8500", "PCI Express Port B0" } , + { 0x8086, 0x2605, "E8500", "PCI Express Port B1" } , + { 0x8086, 0x2606, "E8500", "PCI Express Port A0" } , + { 0x8086, 0x2607, "E8500", "PCI Express Port A1" } , + { 0x8086, 0x2640, "82801FB/FR", "LPC Interface Bridge" } , + { 0x8086, 0x2641, "82801FBM", "LPC Interface Bridge (ICH6-M)" } , + { 0x8086, 0x2651, "82801Fb", "SATA Controller" } , + { 0x8086, 0x2652, "82801FR", "SATA RAID Controller" } , + { 0x8086, 0x2652, "82801FR/FRW", "SATA Controller" } , + { 0x8086, 0x2652, "82801FR/FRW", "SATA Raid Controller" } , + { 0x8086, 0x2652, "82801FR/FRW", "AHCI Controller" } , + { 0x8086, 0x2653, "82801FBM", "SATA AHCI Controller" } , + { 0x8086, 0x2653, "82801FBM", "SATA IDE Controller" } , + { 0x8086, 0x2653, "82801FBM", "AHCI Controller" } , + { 0x8086, 0x2658, "82801FB/FR/FW/FRW", "USB UHCI Controller #1" } , + { 0x8086, 0x2659, "82801FB/FR/FW/FRW", "USB UHCI Controller #2" } , + { 0x8086, 0x265A, "82801FB/FR/FW/FRW", "USB UHCI Controller #3" } , + { 0x8086, 0x265B, "82801FB/FR/FW/FRW", "USB UHCI Controller #4" } , + { 0x8086, 0x265C, "82801FB/FR/FW/FRW", "USB 2.0 EHCI Controller" } , + { 0x8086, 0x2660, "82801FB/FR/FW/FRW", "PCI Express Port 1" } , + { 0x8086, 0x2662, "82801FB/FR/FW/FRW", "PCI Express Port 2" } , + { 0x8086, 0x2664, "82801FB", "PCI Express Port 3" } , + { 0x8086, 0x2666, "82801FB/FR/FW/FRW", "PCI Express Port 4" } , + { 0x8086, 0x2668, "11583659", "82801FB (ICH6) High Definition Audio Controller" } , + { 0x8086, 0x2669, "2028026", "jkn " } , + { 0x8086, 0x266A, "82801BA/CA", "SMBus Controller" } , + { 0x8086, 0x266C, "82801FB/FR/FW/FRW", "LAN Controller" } , + { 0x8086, 0x266D, "82801I", "INTEL 82801FB ICH6-AC'97 AUDIO CONTROLLER" } , + { 0x8086, 0x266E, "Intel Corporation 82830M/MG SDRAM Controller / Ho", "AC '97 Audio Controller/ Sigmatel (SoundMAX Integrated Digital Audio)" } , + { 0x8086, 0x266F, "82801FB/FBM/FW/FR/FRW", "PATA100 Controller - 266F" } , + { 0x8086, 0x2681, "62089A2", "LSI LOGIC, 62089A2, LSISAS1068 B0, T 0620, WE 119200.1" } , + { 0x8086, 0x2770, "82945G/GZ/P/PL", "Host Bridge/DRAM Controller" } , + { 0x8086, 0x2771, "82945G/GZ/P/PL", "Host to PCI Express Bridge" } , + { 0x8086, 0x2772, "82945G/GZ", "Integrated Graphics Device" } , + { 0x8086, 0x277C, "82975X", "Intel 975X Express Chipset" } , + { 0x8086, 0x2780, "82915G", "Graphics device" } , + { 0x8086, 0x2782, "82915G", "Graphics device: 82915G/GV/910GL Express Chipset Family" } , + { 0x8086, 0x2792, "Mobile 82915GLx/x/x", "Mobile Intel(R) 915GM/GMS/, 910GML Express Chipset Family" } , + { 0x8086, 0x27A0, "874079", "i945GM Express Chipset" } , + { 0x8086, 0x27A2, "82940GML", "Mobile Intel(R) 945 Express Chipset Family" } , + { 0x8086, 0x27A6, "945GM", "Intel 945GM/950" } , + { 0x8086, 0x27B8, "945GL", "Intel 82801GB/GR (ICH7 Family) LPC Interface Controller - 27B8" } , + { 0x8086, 0x27c0, "82801GB/GR/GH", "82801 GB Serial ATA Storage Controllers" } , + { 0x8086, 0x27C1, "82801GB/GR/GH", "AHCI Controller" } , + { 0x8086, 0x27c3, "82801GR/GH", "Raid Controller" } , + { 0x8086, 0x27c4, "82801GBM/GHM", "SATA IDE Controller" } , + { 0x8086, 0x27C5, "82801GBM/GHM", "AHCI Controller" } , + { 0x8086, 0x27C6, "82801GHM", "Raid Controller" } , + { 0x8086, 0x27c8, "-", "USB UHCI Controller" } , + { 0x8086, 0x27c9, "-", "USB UHCI Controller" } , + { 0x8086, 0x27CA, "-", "USB UHCI Controller" } , + { 0x8086, 0x27CB, "", "USB UHCI Controller" } , + { 0x8086, 0x27d8, "26331019", "INTEL" } , + { 0x8086, 0x27D8, "945GME", "Intel core2duo" } , + { 0x8086, 0x27d8, "", "Microsoft UAA Bus HD Audio" } , + { 0x8086, 0x27DA, "1B761019", "SMBus Controller XP driver" } , + { 0x8086, 0x27DC, "Intel PRO/100", "Intel(R) PRO/100 VE Network Connection" } , + { 0x8086, 0x27df, "82801GB/GBM/GR/GH/GHM", "PATA100" } , + { 0x8086, 0x2820, "82801HB/HR/HH/HO", "SATA IDE Controller:4 port" } , + { 0x8086, 0x2821, "82821HR/HH/HO", "AHCI Controller" } , + { 0x8086, 0x2822, "82801HR/HH/HO&82801IR/IH/IO(AIE=0)/ICH10R", "Raid Controller" } , + { 0x8086, 0x2824, "82801HB", "ICH8 AHCI Controller" } , + { 0x8086, 0x2825, "82801HB/HR/HH/HO", "SATA IDE Controller:2 port" } , + { 0x8086, 0x2828, "82801HBM/HEM", "SATA IDE Controller" } , + { 0x8086, 0x2829, "82801HBM/HEM", "AHCI Controller" } , + { 0x8086, 0x282A, "ICH8ME/9ME", "Raid Controller" } , + { 0x8086, 0x283A, "81EC1043 (?)", "ICH8 Enhanced USB2 Enhanced Host Controller" } , + { 0x8086, 0x284B, "82801H", "Intel audio controller embedded with the 82801H chipset ( ICH8 chipset )" } , + { 0x8086, 0x2850, "82801HBM/HEM", "PATA Controller" } , + { 0x8086, 0x2920, "82801(IB)/IR/IH/IO", "SATA IDE Controller:4 port" } , + { 0x8086, 0x2921, "82801IR/IH/IO", "SATA IDE Controller:2 port1" } , + { 0x8086, 0x2922, "82801IR/IH/IO", "AHCI Controller" } , + { 0x8086, 0x2923, "82801IB", "ICH9 AHCI Controller" } , + { 0x8086, 0x2925, "82801IR/IH/IO(AIE=1)", "Raid Controller" } , + { 0x8086, 0x2926, "82801IR/IH/IO", "SATA IDE Controller:2 port2" } , + { 0x8086, 0x2928, "?(ICH9M Family)", "SATA IDE Controller:2port1" } , + { 0x8086, 0x2929, "ICH9M/ME", "ICH9M/ME AHCI Controller" } , + { 0x8086, 0x292D, "?(ICH9M Family)", "SATA IDE Controller:2port2" } , + { 0x8086, 0x292E, "?(ICH9M Family)", "SATA IDE Controller:1port2" } , + { 0x8086, 0x2930, "?", "ICH9 Family SMBus Controller" } , + { 0x8086, 0x293E, "486486", "82801IB/IR/IH (ICH9 Family) HD Audio Controller" } , + { 0x8086, 0x294C, "82566DC-2", "Intel(R) 82566DC-2 Gigabit Network Connection" } , + { 0x8086, 0x2972, "82946GZ ", "Onboard Video Device for 82946GZ chips" } , + { 0x8086, 0x2987, "Q965/Q963", "Intel PCI Serial Port" } , + { 0x8086, 0x2992, "", "Intel(R) Express Chipset video" } , + { 0x8086, 0x2993, "", "Intel(R) Express Chipset (Dell Version)" } , + { 0x8086, 0x2994, "0x8086", "Intel(R) Management Engine Interface" } , + { 0x8086, 0x2997, "Q965/Q963", "Intel PCI Serial Port" } , + { 0x8086, 0x29a0, "?(82P965)", "Intel P965/G965 Processor to I/O Controller" } , + { 0x8086, 0x29a1, "?(82Q965, 82G965, 82P965)", "Intel P965/G965 PCI Express Root Port" } , + { 0x8086, 0x29A4, "n/a", "The Intel Management Engine provides thermal management for Intel Desktop Boards." } , + { 0x8086, 0x29B2, "Q35", "Intel(R) Q35 Express Chipset Family" } , + { 0x8086, 0x29B3, "Q35", "Intel" } , + { 0x8086, 0x29B4, "Q35-Chipset", "Intel(R) Management Engine Interface (HECI)" } , + { 0x8086, 0x29B7, "Q35-Chipset", "Serial Over LAN" } , + { 0x8086, 0x29C2, "82G33", "Intel(R) G33 chipset GMA3100 video" } , + { 0x8086, 0x29D4, "82801", "Intel Management Interface" } , + { 0x8086, 0x2A02, "02091028", "Intel GM965, Intel X3100" } , + { 0x8086, 0x2A03, "82Q965", "Intel GM" } , + { 0x8086, 0x2A04, "Q965/Q96", "Intel PCI communication controller" } , + { 0x8086, 0x2A07, "Q965/Q963", "Intel PCI Serial Port" } , + { 0x8086, 0x2A08, "Q965 Chipset", "Intel(R) Extended Thermal Model MCH" } , + { 0x8086, 0x2A44, "unknown", "unknown" } , + { 0x8086, 0x2a47, "20EC17AA", "Active Management Technology - SOL" } , + { 0x8086, 0x2f00, "815B104D", "multimedia audio device (codec AC97) SoundMAX or VIA" } , + { 0x8086, 0x3092, "SRCU32", "I2O 1.5 RAID Controller" } , + { 0x8086, 0x3200, "31244", "PCI-X to Serial ATA Controller" } , + { 0x8086, 0x3340, "82855PM", "Host-Hub Interface Bridge" } , + { 0x8086, 0x3341, "82855PM", "AGP Bridge" } , + { 0x8086, 0x3342, "82855PM", "Power Management" } , + { 0x8086, 0x348D, "82541EI", "Gigabit Ethernet Controller" } , + { 0x8086, 0x3575, "82830[MP]", "Host-Hub I/F Bridge / SDRAM Controller" } , + { 0x8086, 0x3576, "82830M/MP", "Host-AGP Bridge" } , + { 0x8086, 0x3577, "82830M/MG", "Integrated Graphics Device" } , + { 0x8086, 0x3578, "82830[MP]", "CPU to I/O Bridge" } , + { 0x8086, 0x3579, "82835", "SDRAM Controller / Host-hub Interface" } , + { 0x8086, 0x357B, "82835", "Integrated Graphics Device" } , + { 0x8086, 0x3580, "852GM/GMV", "Host-Hub Interface Bridge" } , + { 0x8086, 0x3581, "82852GME/PM", "Virtual PCI to AGP Bridge" } , + { 0x8086, 0x3582, "852GM/GMV", "Integrated Graphics Device" } , + { 0x8086, 0x3584, "852GM/GMV", "System Memory Controller" } , + { 0x8086, 0x3585, "852GM", "Configuration Process" } , + { 0x8086, 0x3590, "E7520", "Memory Controller Hub" } , + { 0x8086, 0x3591, "E7520", "Memory Controller Hub" } , + { 0x8086, 0x3592, "E7320", "Memory Controller Hub" } , + { 0x8086, 0x3593, "E7525", "MCH Error Reporting Registers" } , + { 0x8086, 0x3594, "E7520", "DMA Controller Registers" } , + { 0x8086, 0x3595, "E7525", "PCI Express Port A" } , + { 0x8086, 0x3596, "E7525", "PCI Express Port B" } , + { 0x8086, 0x3597, "E7525", "PCI Express Port B" } , + { 0x8086, 0x3598, "E7520", "PCI Express Port B1" } , + { 0x8086, 0x3599, "E7520", "PCI Express Port C" } , + { 0x8086, 0x359A, "E7520", "PCI Express Port C1" } , + { 0x8086, 0x359B, "E7525", "Extended Configuration Registers" } , + { 0x8086, 0x359E, "E7525", "MCH Control Registers" } , + { 0x8086, 0x360B, "", "who knows&erka" } , + { 0x8086, 0x3A00, "ICH10 Family", "SATA2(4Port1)" } , + { 0x8086, 0x3A02, "ICH10R", "ICH10R AHCI" } , + { 0x8086, 0x3A03, "ICH10", "ICH10 AHCI" } , + { 0x8086, 0x3A06, "ICH10 Family", "SATA2(2Port1)" } , + { 0x8086, 0x3A20, "ICH10 Family", " SATA2(4Port2)" } , + { 0x8086, 0x3A22, "ICH10R", "AHCI Controller" } , + { 0x8086, 0x3A23, "ICH10", "ICH10 AHCI" } , + { 0x8086, 0x3A26, "ICH10 Family", "SATA2(2Port2)" } , + { 0x8086, 0x3A30, "50011458", "SMB controller " } , + { 0x8086, 0x4000, "Creatix", "V.90 HaM Modem" } , + { 0x8086, 0x4220, "MPCI3B", " driverIntel PRO/Wireless 2200BG" } , + { 0x8086, 0x4222, "10418086", "Intel 3945ABG Wireless LAN controller" } , + { 0x8086, 0x4223, "2915ABG", "Intel (R) PRO/Wireless 2200BG Network Connection, (R) PRO/Wireless 2915ABG Network Connection" } , + { 0x8086, 0x4224, "Intel Pro Wireless 2915ABG", "802.11a/b/g WLan adapter" } , + { 0x8086, 0x4227, "3945ABG", "Intel(R) PRO/Wireless 3945ABG" } , + { 0x8086, 0x4229, "Intel 4965AGN", "Intel Wireless WiFi Link 4965AGN(supporting 802.11a/b/g/Draft-N)" } , + { 0x8086, 0x422D, "Intel 4965AGN", "Intel Wireless WiFi Link 4965AGN" } , + { 0x8086, 0x4230, "Intel 4965AGN", "Intel Wireless WiFi Link 4965AGN" } , + { 0x8086, 0x4232, "Intel WiFi Link 5100", "Carte Intel WiFi Link 5100 AGN" } , + { 0x8086, 0x4233, "Intel 4965AGN", "Intel Wireless WiFi Link 4965AGN" } , + { 0x8086, 0x4235, "5300AGN", "Intel WiFi Link 5300 AGN" } , + { 0x8086, 0x4237, "5100 AGN", "Intel (R) WiFi Link 5100 AGN" } , + { 0x8086, 0x444E, "TurboMemory", "Intel TurboMemory" } , + { 0x8086, 0x5001, "PRO/DSL 2100", "Modem - PPP" } , + { 0x8086, 0x5005, "PRO/DSL 2200", "Modem - PPPoA" } , + { 0x8086, 0x5029, "?(EP80579)", "AHCI Controller" } , + { 0x8086, 0x5200, "NH82801GR", "PCI to PCI Bridge" } , + { 0x8086, 0x5201, "", "Network Controller" } , + { 0x8086, 0x5309, "80303", "I/O Processor Address Translation Unit" } , + { 0x8086, 0x530D, "80312", "I/O Companion Unit Address Translation" } , + { 0x8086, 0x6960, "", "EHCI 960 emulator" } , + { 0x8086, 0x7000, "82371SB", "PIIX3 PCI-to-ISA Bridge (Triton II)" } , + { 0x8086, 0x7010, "82371SB", "PIIX3 IDE Interface (Triton II)" } , + { 0x8086, 0x7020, "82371SB", "PIIX3 USB Host Controller (Triton II)" } , + { 0x8086, 0x7030, "82437VX", "System Controller" } , + { 0x8086, 0x7051, "PB 642365-003", "Intel Business Video Conferencing Card" } , + { 0x8086, 0x7100, "82439TX", "System Controller (MTXC), part of 430TX chipset" } , + { 0x8086, 0x7110, "82371AB/EB/MB", "PIIX4/4E/4M ISBridgeA " } , + { 0x8086, 0x7111, "82371AB/EB/MB", "PIIX4/4E/4M IDE Controller" } , + { 0x8086, 0x7112, "82371AB/EB/MB", "PIIX4/4E/4M USB Interface" } , + { 0x8086, 0x7113, "82371AB/EB/MB", "PIIX4/4E/4M Power Management Controller" } , + { 0x8086, 0x7120, "82810", "Host-Hub Interface Bridge / DRAM Ctrlr" } , + { 0x8086, 0x7121, "82810", "Graphics Controller" } , + { 0x8086, 0x7122, "82810-DC100", "Host-Hub Interface Bridge / DRAM Ctrlr" } , + { 0x8086, 0x7123, "82810-DC100", "Intel� 82810 Graphics Controller" } , + { 0x8086, 0x7124, "82810E", "Host-Hub Interface Bridge / DRAM Ctrlr" } , + { 0x8086, 0x7125, "82810E", "Intel Direct AGP 810 Chipset" } , + { 0x8086, 0x7126, "82810-DC133", "Host Bridge and Memory Controller Hub" } , + { 0x8086, 0x7127, "82810-DC133", "Graphics Device (FSB 133 MHz)" } , + { 0x8086, 0x7128, "82810-M DC-100", "Host Bridge and Memory Controller Hub" } , + { 0x8086, 0x712A, "82810-M DC-133", "Host Bridge and Memory Controller Hub" } , + { 0x8086, 0x7180, "rmc", "Host/PCI bridge in 440LX/EX AGP chipset" } , + { 0x8086, 0x7181, "82443 ex/lx", "AGP device in 440LX/EX AGP chipset" } , + { 0x8086, 0x7182, "440LX/EX", "intel" } , + { 0x8086, 0x7190, "82443BX/ZX", "440BX/ZX AGPset Host Bridge" } , + { 0x8086, 0x7191, "82443BX/ZX", "440BX/ZX AGPset PCI-to-PCI bridge" } , + { 0x8086, 0x7192, "82443BX/ZX", "440BX/ZX chipset Host-to-PCI Bridge" } , + { 0x8086, 0x7194, "82443MX", "AC'97 Audio device" } , + { 0x8086, 0x7195, "82443MX", "AC97 Audio Controller" } , + { 0x8086, 0x7196, "82440 - 443MX", "AC97 Modem Controller (Winmodem)" } , + { 0x8086, 0x7198, "82443MX", "PCI to ISA Bridge" } , + { 0x8086, 0x7199, "82443MX", "EIDE Controller" } , + { 0x8086, 0x719A, "82443MX", "USB Universal Host Controller" } , + { 0x8086, 0x719B, "82443MX", "Power Management Controller" } , + { 0x8086, 0x71A0, "82443GX", "Host-to-PCI Bridge" } , + { 0x8086, 0x71A1, "intel 82801 IB ICH9 - high definition audio", "Intel" } , + { 0x8086, 0x71A2, "82443GX", "Host-to-PCI Bridge" } , + { 0x8086, 0x7221, "82810", "graphics device" } , + { 0x8086, 0x7600, "82372FB/82468GX", "LPC/FWH Interface" } , + { 0x8086, 0x7601, "82372FB/82468GX", "EIDE Controller" } , + { 0x8086, 0x7602, "82372FB/82468GX", "USB Host Controller" } , + { 0x8086, 0x7603, "82372FB/82468GX", "SM Bus Controller" } , + { 0x8086, 0x7605, "82372FB", "IEEE1394 OpenHCI Host Controller" } , + { 0x8086, 0x7800, "82740", "AGP Graphics Accelerator" } , +// { 0x8086, 0x8086, "park55", "lsdurjlk" } , +// { 0x8086, 0x8086, "", "" } , + { 0x8086, 0x8086, "(0x2994)", "Intel(R) Management Engine Interface" } , + { 0x8086, 0x811A, "Atom SCH", "Atom SCH PATA" } , + { 0x8086, 0x84C4, "82454KX/GX", "450KX/GX PCI Bridge (Orion)" } , + { 0x8086, 0x84C5, "82453KX/GX", "450KX/GX Memory Controller (Orion)" } , + { 0x8086, 0x84CA, "82451NX", "450NX PCIset Memory & I/O Controller" } , + { 0x8086, 0x84CB, "82454NX/82467GX", "PCI Expander Bridge" } , + { 0x8086, 0x84E0, "82461GX", "System Address controller" } , + { 0x8086, 0x84E1, "82462GX", "System Data Controller" } , + { 0x8086, 0x84E2, "82465GX", "Graphics Expander Bridge" } , + { 0x8086, 0x84E3, "82463GX", "Memory Address Controller" } , + { 0x8086, 0x84E4, "82464GX", "Memory Data Controller" } , + { 0x8086, 0x84E6, "82466GX", "Wide and fast PCI eXpander Bridge" } , + { 0x8086, 0x84EA, "82460GX", "AGP Bridge (GXB function 1)" } , + { 0x8086, 0x85A1, "6300ESB", "LPC Bridge" } , + { 0x8086, 0x85A2, "6300ESB", "IDE Controller" } , + { 0x8086, 0x85A3, "6300ESB", "Serial ATA Controller" } , + { 0x8086, 0x85A4, "6300ESB", "SMBus Controller" } , + { 0x8086, 0x85A6, "6300ESB", "AC'97 Audio Controller" } , + { 0x8086, 0x85A7, "6300ESB", "AC'97 Modem Controller" } , + { 0x8086, 0x85A9, "6300ESB", "USB 1.1 UHCI Controller #1" } , + { 0x8086, 0x85AA, "6300ESB", "USB 1.1 UHCI Controller #2" } , + { 0x8086, 0x9620, "", "I2O RAID PCI to PCI Bridge" } , + { 0x8086, 0x9621, "SRCU21", "I2O 1.5 RAID Controller" } , + { 0x8086, 0x9622, "SRCUxx", "I2O 1.5 RAID Controller" } , + { 0x8086, 0x9641, "SRCU31", "I2O 1.5 RAID Controller" } , + { 0x8086, 0x96A1, "SRCU31L", "I2O 1.5 RAID Controller" } , + { 0x8086, 0x9874, "AC97", "AUDIO CONTROLLER" } , + { 0x8086, 0x9876, "i845", "intel brokdale" } , + { 0x8086, 0xB152, "S21152BB", "PCI to PCI Bridge" } , + { 0x8086, 0xB154, "S21154AE/BE", "PCI to PCI Bridge" } , + { 0x8086, 0xB555, "21555", "Non-Transparent PCI-to-PCI Bridge" } , + { 0x8086, 8671, "", "" } , + { 0x80EE, 0xBEEF, "BGA", "Bochs/Qemu Graphics Adapter (VirtualBox)" } , + { 0x80EE, 0xCAFE, "VMMDEV", "Guest Additions device" } , + { 0x9004, 0x0078, "aic-7880p", "AHA-2940UW/CN" } , + { 0x9004, 0x1078, "AIC-7810C", "RAID Coprocessor" } , + { 0x9004, 0x1135, "0x0035", "Texas Instruments" } , + { 0x9004, 0x1160, "AIC-1160", "Fibre Channel Adapter" } , + { 0x9004, 0x2178, "AIC-7821", "SCSI Controller" } , + { 0x9004, 0x3860, "", "AIC-2930U Ultra SCSI Ctrlr" } , + { 0x9004, 0x3B78, "AHA-4944W/4944UW", "QuadChannel Fast-Wide/Ultra-Wide Diff. SCSI Ctrlr" } , + { 0x9004, 0x5075, "AIC-755x", "SCSI Ctrlr" } , + { 0x9004, 0x5078, "AIC-7850P", "Fast/Wide SCSI Controller" } , + { 0x9004, 0x5175, "AIC-755x", "SCSI Ctrlr" } , + { 0x9004, 0x5178, "AIC-7850", "FAST-SCSI Ctrlr" } , + { 0x9004, 0x5275, "AIC-755x", "SCSI Ctrlr" } , + { 0x9004, 0x5278, "AIC-7850", "Fast SCSI Ctrlr" } , + { 0x9004, 0x5375, "AIC-755x", "SCSI Ctrlr" } , + { 0x9004, 0x5378, "AIC-7850", "Fast SCSI Ctrlr" } , + { 0x9004, 0x5475, "AIC-755x", "SCSI Ctrlr" } , + { 0x9004, 0x5478, "AIC-7850", "Fast SCSI Ctrlr" } , + { 0x9004, 0x5575, "AVA-2930", "SCSI Ctrlr" } , + { 0x9004, 0x5578, "AIC-7855", "Fast SCSI Ctrlr" } , + { 0x9004, 0x5675, "AIC-755x", "SCSI Ctrlr" } , + { 0x9004, 0x5678, "AIC-7856", "Fast SCSI Ctrlr" } , + { 0x9004, 0x5775, "AIC-755x", "SCSI Ctrlr" } , + { 0x9004, 0x5778, "AIC-7850", "Fast SCSI Ctrlr" } , + { 0x9004, 0x5800, "AIC-5800", "PCI-to-1394 Ctrlr" } , + { 0x9004, 0x5900, "ANA-5910/30/40", "ATM155 & 25 LAN Controller" } , + { 0x9004, 0x5905, "ANA-5910A/30A/40A", "ATM Adpater" } , + { 0x9004, 0x6038, "AHA-2930C", "Ultra SCSI Adpater (VAR)" } , + { 0x9004, 0x6075, "AIC-7560?", "CardBus Ultra SCSI Controller" } , + { 0x9004, 0x6078, "AIC-7860", "PCI SCSI Controller" } , + { 0x9004, 0x6178, "AIC-7861", "PCI SCSI Controller" } , + { 0x9004, 0x6278, "AIC-7860", "SCSI Ctrlr" } , + { 0x9004, 0x6378, "AIC-7860", "SCSI Ctrlr" } , + { 0x9004, 0x6478, "AIC-786x", "SCSI Ctrlr" } , + { 0x9004, 0x6578, "AIC-786x", "SCSI Ctrlr" } , + { 0x9004, 0x6678, "AIC-786x", "SCSI Ctrlr" } , + { 0x9004, 0x6778, "AIC-786x", "SCSI Ctrlr" } , + { 0x9004, 0x6915, "ANA620xx/69011A", "Fast Ethernet" } , + { 0x9004, 0x7078, "AIC-7870", "Fast and Wide SCSI Ctrlr" } , + { 0x9004, 0x7178, "AHA-2940/2940W", "Fast/Fast-Wide SCSI Ctrlr" } , + { 0x9004, 0x7278, "AHA-3940/3940W", "Multichannel Fast/Fast-Wide SCSI Ctrlr" } , + { 0x9004, 0x7378, "AHA-3985", "4-chan RAID SCSI Ctrlr" } , + { 0x9004, 0x7478, "AHA-2944", "SCSI Ctrlr" } , + { 0x9004, 0x7578, "AHA-3944/3944W", "Multichannel Fast/Fast-Wide Diff. SCSI Ctrlr" } , + { 0x9004, 0x7678, "AHA-4944W/4944UW", "QuadChannel Fast-Wide/Ultra-Wide Diff. SCSI Ctrlr" } , + { 0x9004, 0x7778, "AIC-787x", "SCSI Ctrlr" } , + { 0x9004, 0x7810, "aic 7810", "Memory control IC" } , + { 0x9004, 0x7815, "AIC-7515", "RAID + Memory Controller IC" } , + { 0x9004, 0x7850, "aic-7850", "Fast/Wide SCSI-2 Controller" } , + { 0x9004, 0x7855, "AHA-2930", "Single channel SCSI Host Adapter" } , + { 0x9004, 0x7860, "AIC-7860", "PCI SCSI Controller" } , + { 0x9004, 0x7870, "AIC-7870", "Fast/Wide SCSI-2 Controller" } , + { 0x9004, 0x7871, "aha 2940", "SCSI" } , + { 0x9004, 0x7872, "aha 3940", "Multiple SCSI channels" } , + { 0x9004, 0x7873, "aha 3985", "Multiple SCSI channels" } , + { 0x9004, 0x7874, "aha 2944", "Differential SCSI" } , + { 0x9004, 0x7880, "aic7880p", "Fast 20 SCSI" } , + { 0x9004, 0x7890, "AIC-7890", "SCSI controller" } , + { 0x9004, 0x7891, "AIC-789x", "SCSI controller" } , + { 0x9004, 0x7892, "AIC-789x", "SCSI controller" } , + { 0x9004, 0x7893, "AIC-789x", "SCSI controller" } , + { 0x9004, 0x7894, "AIC-789x", "SCSI controller" } , + { 0x9004, 0x7895, "AIC-7895", "Ultra-Wide SCSI Ctrlr on AHA-2940 AHA-394x" } , + { 0x9004, 0x7896, "AIC-789x", "SCSI controller" } , + { 0x9004, 0x7897, "AIC-789x", "SCSI controller" } , + { 0x9004, 0x8078, "AIC-7880", "Ultra Wide SCSI" } , + { 0x9004, 0x8178, "AHA-2940U/2940UW", "Ultra/Ultra-Wide SCSI Ctrlr" } , + { 0x9004, 0x8278, "AHA-3940Uxx", "AHA-3940U/3940UW/3940UWD SCSI Ctrlr" } , + { 0x9004, 0x8378, "AIC-7883U", "SCSI Controller" } , + { 0x9004, 0x8478, "ADAPTEC 2940UW CN SCSI", "Ultra-Wide Diff. SCSI Ctrlr" } , + { 0x9004, 0x8578, "AHA-3944U/3944UWD", "Fast-Wide/Ultra-Wide Diff. SCSI Ctrlr" } , + { 0x9004, 0x8678, "AHA-4944UW", "QuadChannel Ultra-Wide Diff. SCSI Ctrlr" } , + { 0x9004, 0x8778, "AIC-788x", "Ultra-Wide SCSI Ctrlr" } , + { 0x9004, 0x8878, "AIC-7888?", "Ultra Wide SCSI Controller" } , + { 0x9004, 0x8B78, "ABA-1030", "AIC-7880P" } , + { 0x9004, 0xEC78, "AHA-4944W/4944UW", "QuadChannel Fast-Wide/Ultra-Wide Diff. SCSI Ctrlr" } , + { 0xD4D4, 0x010F, "PMC-211", "PMC-211" } , + { 0xD4D4, 0x0601, "", "PCI Mezzanine Card" } , + { 0xDEAF, 0x9050, "", "PC Weasel PCI VGA Device" } , + { 0xDEAF, 0x9051, "", "PC Weasel PCI Serial Comm. Device" } , + { 0xDEAF, 0x9052, "", "PC Weasel PCI" } , + { 0xE159, 0x0001, "Ambient MD3200 A", "Intel 537 Data Fax Voice v.92 Modem" } , + { 0xE159, 0x0002, "", "Sedlbauer Speed PCI" } , + { 0xE159, 0x0600, "Tiger 600", "PCI-to-PCI Bridge" } , + { 0xEDD8, 0xA091, "ARK1000PV", "Stingray GUI Accelerator" } , + { 0xEDD8, 0xA099, "ARK2000PV", "Stingray GUI Accelerator" } , + { 0xEDD8, 0xA0A1, "ARK2000MT", "Stingray 64" } , + { 0xEDD8, 0xA0A9, "ARK2000MI", "Quadro645 GUI Accelerator" } , + { 0xEDD8, 0xA0B1, "ARK2000MI+", "GUI Accelerator" } , + { 0x1519, 0x2004, "0x1", "PCI Interface bus" } , + { 0x151B, 0x9080, "me594v02100 combox", "combox cb 300a" } , + { 0x151F, 0x0001, "TOPIC FM-56PCI-TP", "TOPIC FM-56PCI-TP" } , + { 0x151F, 0x0568, "1.0.1.8", "56k Internal Data Fax Voice Modem" } , + { 0x1435, 0x0531, "DELETE", "DELETE" } , + { 0x1435, 0x6020, "SPM6020", "PCI-104 dspModule" } , + { 0x1435, 0x6030, "SPM6030", "PC/104-Plus dspModule" } , + { 0x1435, 0x6420, "SPM186420", "PC/104-Plus dspModule" } , + { 0x1435, 0x6430, "SPM176430", "PC/104-Plus dspModule" } , + { 0x1435, 0x7520, "DM7520", "PC/104-Plus dataModule" } , + { 0x1435, 0x7540, "SDM7540", "PC/104-Plus dataModule with SmartCal" } , + { 0x1523, 0x8, "MU9C8K64", "Content Addressable Memory" } , + { 0x1524, 0x0510, "1.4.5.0", "PCI Memory Card Reader Controller" } , + { 0x1524, 0x0530, "CB-712/714/810", "Memory Stick Card Reader" } , + { 0x1524, 0x0550, "CB-712/714/810", "Secure Digital Card Reader" } , + { 0x1524, 0x0610, "???", "PCI Smart Card Reader Controller" } , + { 0x1524, 0x1211, "CB-1211", "CardBus Controller" } , + { 0x1524, 0x1225, "CB-1225", "CardBus Controller" } , + { 0x1524, 0x1410, "CB-1420", "CardBus Controller" } , + { 0x1524, 0x1411, "CB-710/2/4/810", "Cardbus Controller" } , + { 0x1524, 0x1412, "CB-712/4", "Cardbus Controller" } , + { 0x1524, 0x1420, "CB-1420", "CardBus Controller" } , + { 0x1524, 0x1421, "CB-720/2/4", "CardBus Controller" } , + { 0x1524, 0x1422, "CB-722/4", "CardBus Controller" } , + { 0x1524, 0x510, "1.4.5.0", "PCI Memory Card Reader Controller" } , + { 0x1538, 0x0301, "?", "Tekram DC200 PATA100 RAID Controller" } , + { 0x153B, 0x1115, "ICE1712 Envy24", "IC Ensemble Inc ICE1712 Envy24 Multichannel Audio Controller" } , + { 0x153B, 0x1143, "SAA7134HL", "Philips Semiconductors SAA7134HL Multimedia Capture Device" } , + { 0x153B, 0x6003, "CS4614/22/24", "CrystalClear SoundFusion PCI Audio Accel" } , + { 0x153F, 0xdead, "xx12345", "Not a chip ..." } , + { 0x1540, 0x9524, "saa7134", "PAL/SECAM TV card w/ FM1216ME MK3 tuner (+FM radio)" } , + { 0x1693, 0x0212, "PLX PCI9054", "EPONINE ESR-PCI Board" } , + { 0x1693, 0x0213, "Motorola MPC8245", "EPONINE MTM120 PCI Board" } , + { 0x170B, 0x0100, "NSP2000-SSL", "Crypto Aceletator" } , + { 0x1743, 0x8139, "ROL/F-100", "Fast Ethernet Adapter with ROL" } , + { 0x1522, 0x0100, "PBridge+", "PCI Interface Chip" } , + { 0x1543, 0x3052, "30201543", "Modem Intel 537EP (Chipset KAIOMY)" } , + { 0x1543, 0x3155, "Unknown", "Modem Device on High Definition Audio Bus" } , + { 0x1555, 0x0002, "PLX PCI 9050", "Easylon PCI Bus Interface" } , + { 0x1549, 0x80FF, "PCI-ISA-001", "PCI/ISA Bus Bridge" } , + { 0x1558, 0x1558, "", "" } , + { 0x155E, 0x0020, "MFC3", "Multi Function Card Version 3" } , + { 0x1562, 0x0001, "LA-41x3", "Spectrum24 Wireless LAN PCI Card" } , + { 0x1562, 0x0002, "LA-5030", "Symbol Wireless Networker 802.11a/g CardBus" } , + { 0x1562, 0x0003, "LA-5033", "Symbol Wireless Networker 802.11a/g PCI" } , + { 0x156A, 0x5000, "NA", "Wideband Advanced Signal Processor" } , + { 0x156A, 0x5100, "NA", "High Data Rate Radio" } , + { 0x16CA, 0x0001, "Rocket Drive", "Solid State Disk" } , + { 0x1571, 0xA001, "CCSI PCI20", "ARCNET backplane" } , + { 0x1571, 0xA002, "CCSI PCI20-485D", "ARCnet" } , + { 0x1571, 0xA003, "CCSI PCI20-485X", "ARCnet" } , + { 0x1571, 0xA004, "CCSI PCI20-CXB", "ARCnet" } , + { 0x1571, 0xA005, "CCSI PCI20-CXS", "ARCnet" } , + { 0x1571, 0xA006, "CCSI PCI20-FOG-SMA", "ARCnet" } , + { 0x1571, 0xA007, "CCSI PCI20-FOG-ST", "ARCnet" } , + { 0x1571, 0xA008, "CCSI PCI20-TB5", "ARCnet" } , + { 0x1571, 0xA009, "CCSI PCI20-5-485", "5 Mbit ARCnet" } , + { 0x1571, 0xA00A, "CCSI PCI20-5-485D", "5 Mbit ARCnet" } , + { 0x1571, 0xA00B, "CCSI PCI20-5-485X", "5 Mbit ARCnet" } , + { 0x1571, 0xA00C, "CCSI PIC20-5-FOG-ST", "5 Mbit ARCnet" } , + { 0x1571, 0xA00D, "CCSI PCI20-5-FOG-SMA", "5 Mbit ARCnet" } , + { 0x1571, 0xA00E, "COM200C22", "ARCNET" } , + { 0x1571, 0xA201, "CCSI PCI22-485", "10 Mbit ARCnet" } , + { 0x1571, 0xA202, "CCSI PCI22-485D", "10 Mbit ARCnet" } , + { 0x1571, 0xA203, "CCSI PCI22-485X", "10 Mbit ARCnet" } , + { 0x1571, 0xA204, "CCSI PCI22-CHB", "10 Mbit ARCnet" } , + { 0x1571, 0xA205, "CCSI PCI22-FOG-ST", "10 Mbit ARCnet" } , + { 0x1571, 0xA206, "CCSI PCI22-THB", "10 Mbit ARCnet" } , + { 0x173B, 0x03E8, "AC1000", "Gigabit Ethernet Adapter" } , + { 0x173B, 0x03EA, "AC1002", "Gigabit Ethernet Adapter" } , + { 0x1584, 4003, "", "" } , + { 0x1586, 0x0803, "", "" } , + { 0x1588, 0x1100, "PAX.port 1100", "PAX.ware 1100 dual Gb classifier engine" } , + { 0x1588, 0x2000, "AMD '971", "SNP 8023 packet classifier - AMD component" } , + { 0x1588, 0x8023, "SNP8023", "PAX.ware 100 packet classifier" } , + { 0x158B, 0x0015, "HLF-VMPEU560-C", "Standar HSP Modem Series" } , + { 0x15A2, 0x0001, "TA700", "PCI Bus Analyzer/Exerciser" } , + { 0x17AF, 0x4150, "200", "HIS Excalibur Radeon 9600" } , + { 0x15B0, 0x0001, "FM-1789", "Pctel" } , + { 0x15B0, 0x2BD0, "2BD0", "soft56k voice,data,fax CARP" } , + { 0x15B3, 0x5274, "MT21108", "InfiniBridge" } , + { 0x15B3, 0x6278, "MT25208A0-FCC", "InfiniHost TM III Ex" } , + { 0x15B8, 0x3009, "xPCI-3504", "Analog output board" } , + { 0x15BC, 0x0101, "n2530a", "DX2+ FC-AL Adapter" } , + { 0x15BC, 0x0103, "QX4", "4 Port Fibre Channel Controller" } , + { 0x15BC, 0x2530, "???", "HP Communications Port" } , + { 0x15BC, 0x2531, "???", "HP Toptools Remote Control Adapter" } , + { 0x15BC, 0x2532, "???", "HP Toptools Remote Control Adapter" } , + { 0x15BC, 0x2929, "E2929A", "PCI/PCI-X Bus Analyzer" } , + { 0x1394, 0x0001, "LXT1001", "Gigabit Ethernet Adapter" } , + { 0x15D1, 0x0001, "TC11IB", "TriCore 32-bit Single-chip Microctrlr" } , + { 0x15D1, 0x0003, "PEB 20544 E v1.1", "6 Port Optimized Comm Ctrlr (SPOCC)" } , + { 0x15D1, 0x0004, "PEB 3454 E v1.1", "TE3-SPICCE 6 Port Integrated Comm Ctrlr" } , + { 0x15D7, 0x0056, "hcf cx11252-41z", "hcf 56" } , + { 0x15D8, 0x9001, "", "" } , + { 0x15DD, 0x7664, "vgn-ar71mr", "idt high audio" } , + { 0x15DD, 0x7680, "*", "SIGMATEL STAC 92XX C-Major HD Audio" } , + { 0x15E2, 0x0500, "", "Internet PhoneJack PCI Card" } , + { 0xEACE, 0x3100, "DAG 3.10", "OC-3/OC-12" } , + { 0xEACE, 0x3200, "DAG 3.2x", "OC-3/OC-12" } , + { 0xEACE, 0x320E, "DAG 3.2E", "Fast Ethernet" } , + { 0xEACE, 0x340E, "DAG 3.4E", "Fast Ethernet" } , + { 0xEACE, 0x341E, "DAG 3.41E", "Fast Ethernet" } , + { 0xEACE, 0x3500, "DAG 3.5", "OC-3/OC-12" } , + { 0xEACE, 0x351C, "DAG 3.5ECM", "Fast Ethernet" } , + { 0xEACE, 0x4100, "DAG 4.10", "OC-48" } , + { 0xEACE, 0x4110, "DAG 4.11", "OC-48" } , + { 0xEACE, 0x4200, "DAG 4.2", "OC-48" } , + { 0xEACE, 0x420E, "DAG 4.2E", "Dual Gigabit Ethernet" } , + { 0xEACE, 0x430e, "DAG 4.3E", "Dual Gigabit Ethernet" } , + { 0x15E6, 0x0002, "1646t00", "v.90 Lucent Modem" } , + { 0x15E8, 0x0130, "NCP130", "Wireless NIC" } , + { 0x15E8, 0x0131, "Prism II", "InstantWave HR PCI card" } , + { 0x15E9, 0x1841, "NetStaQ ADMA-100", "ATA controller" } , + { 0x15F1, 0x2F30, "CX11252-15", "Conexant HSFi" } , + { 0x15F2, 0x0001, "Spot RT", "Spot RT Interface Board" } , + { 0x15F2, 0x0002, "Spot RT #2", "Spot RT Interface Board" } , + { 0x15F2, 0x0003, "Spot Insight", "Spot Insight Interface Board" } , + { 0x1619, 0x0400, "FarSync T2P", "Two Port Intelligent Sync Comms Card" } , + { 0x1619, 0x0440, "FarSync T4P", "Four Port Intelligent Sync Comms Card" } , + { 0x1619, 0x0610, "FarSync T1U", "One Port Intelligent Sync Comms Card" } , + { 0x1619, 0x0620, "FarSync T2U", "Two Port Intelligent Sync Comms Card" } , + { 0x1619, 0x0640, "FarSync T4U", "Four Port Intelligent Sync Comms Card" } , + { 0x1619, 0x1610, "FarSync TE1", "One Port Intelligent Sync Comms Card" } , + { 0x1619, 0x1612, "FarSync TE1C", "Channelized Intelligent Sync Comms Card" } , + { 0x1619, 0x2610, "FarSync DSL-S1", "G.SHDSL Intelligent Sync Comms Card" } , + { 0x1619, 0x3640, "FarSync T4E", "Four Port Intelligent Sync Comms Card" } , + { 0x1619, 0x4620, "FarSync T2Ue (PCI Express)", "Two Port Intelligent Sync Comms Card" } , + { 0x1619, 0x4640, "FarSync T4Ue (PCI Express)", "Four Port Intelligent Sync Comms Card" } , + { 0x1621, 0x0020, "LynxTWO-A", "4 in/4 out Professional Digital Audio Card" } , + { 0x1621, 0x0021, "LynxTWO-B", "2 in/6 out Professional Digital Audio Card" } , + { 0x1621, 0x0022, "LynxTWO-C", "6 in/2 out Professional Digital Audio Card" } , + { 0x1621, 0x0023, "Lynx L22", "2 in/2 out Professional Digital Audio Card" } , + { 0x1621, 0x0024, "Lynx AES16", "16 in/16 out AES/EBU Audio Card" } , + { 0x1621, 0x0025, "Lynx AES16-SRC", "16 in/16 out AES/EBU Audio Card w/SRC" } , + { 0x1629, 0x1003, "", "Format Synchronizer v3.0" } , + { 0x1629, 0x2002, "", "Fast Universal Data Output" } , + { 0x162D, 0x0100, "", "Repeographics controller" } , + { 0x162D, 0x0101, "", "Reprographics Controller" } , + { 0x162D, 0x0102, "", "Reprographics Controller" } , + { 0x162D, 0x0103, "", "Reprographics Controller" } , + { 0x162F, 0x1111, "TS-PRL1", "General Purpose Relay Card" } , + { 0x162F, 0x1112, "TS-PMA", "Matrix Card" } , + { 0x1638, 0x1100, "WL11000P", " WL11000P" } , + { 0x163C, 0x3052, "R6793-11", "RS56/HSP-PCI" } , + { 0x163C, 0xFF02, "SL2800 PCI", "SMART LINK 56K VOICE V.92 MODEM" } , + { 0x1734, 0x007a, "Rage XL", "ATI Rage XL (rev 27)" } , + { 0x1734, 0x1011, "AIC-7902W", "Adaptec AIC-7902 Dual Channel U320 SCSI" } , + { 0x1734, 0x1012, "CSB6", "Serverworks Southbridge with RAID/IDE (rev a0), OHCI USB (rev 05), GCLE-2 Host Bridge" } , + { 0x1734, 0x1013, "BCM5703", "Broadcom Corp. NetXtreme Gigabyte Ethernet" } , + { 0x1734, 0x10b9, "0x00541000", "SAS 3000 series, 8-port with 1068 -StorPort" } , + { 0x164F, 0x0001, "PLX 9054", "PCI interface chip" } , + { 0x164F, 0x0002, "PLX 9054", "PCI interaface chip" } , + { 0x1813, 0x3059, "VT8237", "AC97 Enhanced Audio Controller - the 8251 controller is different" } , + { 0x1813, 0x4000, "MD5628D-L-A", "intel V.92 HaM Modem" } , + { 0x1813, 0x4100, "Ambient MD8820", "Intel HaM V.92 Modem" } , + { 0x17D5, 0x5831, "X1", "Xframe 10GbE PCI-X Adapter" } , + { 0x17D5, 0x5832, "X2", "Xframe II 10GbE PCI-X 2.0 Adapter" } , + { 0x17D5, 0x5833, "X3", "E3100 PCI-Express 10Gb Ethernet Interface" } , + { 0xFA57, 0x0001, "PMC", "Pattern Matching Chip" } , + { 0x18CA, 0x0040, "8085", "Volari Family" } , + { 0x18C9, 0x1011, "Leonardo CL", "Video processor" } , + { 0x18C9, 0x1012, "Leonardo CL-P", "Video processor" } , + { 0x18C9, 0x1013, "Leonardo CL-DB", "Video processor" } , + { 0x18C9, 0x1014, "Leonardo CL-P-DB", "Video processor" } , + { 0x18C9, 0x1015, "Leonardo CL-DVR", "Video processor" } , + { 0x18C9, 0x1016, "Leonardo CL-DVR-DB", "Video processor" } , + { 0x18C9, 0x2011, "Picasso 2SQ", "Framegrabber" } , + { 0x18C9, 0x2012, "Picasso 3C/3Cpro", "Framegrabber" } , + { 0x18C9, 0x2013, "Picasso LS", "Framegrabber" } , + { 0x18C9, 0x2014, "Picasso CL", "Framegrabber" } , + { 0x18C9, 0x2015, "Picasso FI", "Framegrabber" } , + { 0x18C9, 0x2016, "Picasso SDI", "Framegrabber" } , + { 0x18C9, 0x2017, "Picasso DUO", "Framegrabber" } , + { 0x18C9, 0x2021, "Colory", "Framegrabber" } , + { 0x18C9, 0x3011, "Valentino", "Video Output Board" } , + { 0x1910, 0x0001, "SW5000-NCA", "Seaway Network Content Accelerator" } , + { 0x1360, 0x0101, "PCI32", "DCF77 Radio Clock" } , + { 0x1360, 0x0102, "PCI509", "DCF77 Radio Clock" } , + { 0x1360, 0x0103, "PCI510", "DCF77 Radio Clock" } , + { 0x1360, 0x0104, "PCI511", "DCF77 Radio Clock" } , + { 0x1360, 0x0105, "PEX511", "DCF77 Receiver" } , + { 0x1360, 0x0201, "GPS167PCI", "GPS Receiver" } , + { 0x1360, 0x0202, "GPS168PCI", "GPS Receiver" } , + { 0x1360, 0x0203, "GPS169PCI", "GPS Receiver" } , + { 0x1360, 0x0204, "GPS170PCI", "GPS Receiver" } , + { 0x1360, 0x0205, "GPS170PEX", "GPS Receiver" } , + { 0x1360, 0x0301, "TCR510PCI", "IRIG Timecode Reader" } , + { 0x1360, 0x0302, "TCR167PCI", "IRIG Timecode Reader" } , + { 0x1360, 0x0303, "TCR511PCI", "IRIG Timecode Reader" } , + { 0x1360, 0x0304, "TCR511PEX", "IRIG Timecode Receiver" } , + { 0x1725, 0x7174, "VSC7174", "VSC7174 PCI/PCI-X SATA Controller" } , + { 0x1753, 0x1001, "VP500", "VolumePro 500" } , + { 0x1753, 0x1004, "VP1000", "VolumePro 1000" } , + { 0x17CC, 0x2280, "Net 2280", "USB 2.0 Device Controller" } , + { 0x14EA, 0xAB06, "FNW-3603-TX", "10/100 Fast Ethernet CardBus (RTL8139)" } , + { 0x12B9, 0x1006, "5610", "5610 56K FaxModem WinModem" } , + { 0x12B9, 0x1007, "AD1807JS", "US Robotics 56K DATA FAX WINMODEM" } , + { 0x12B9, 0x1008, "USR5610B", "USR5610B (0005610-02) 56K Performance Pro Modem (PCI Internal)" } , + { 0x12B9, 0x3F0, "3CP2977", "US Robotics 56K Fax PCI aka Model 0726, V.90 56K Internal Faxmodem" } , + { 0x1814, 0x0101, "2460 802.11b", "RT2460 802.11b Baseband/MAC integrated chip" } , + { 0x1814, 0x0201, "0x03011814", "Ralink Chipset 802.11b/g WLAN Card" } , + { 0x1814, 0x0201, "", "W-LAN 802.11b/g" } , + { 0x1814, 0x0201, "RT2560F", "RaLink" } , + { 0x1814, 0x0301, "b8341462", "Edimax 54 MBit WLan 802.11g rt 2500" } , + { 0x1814, 0x0302, "RT2525 2.4GHz transceiver + RT2560 MAC/BBP", "wireless a/b" } , + { 0x1814, 0x0781, "RT2860/RT2890", "Wireless" } , + { 0x1103, 0x0003, "HPT 343/345/363", "EIDE Controller" } , + { 0x1103, 0x0004, "HPT366/368/370/370A", "ATA Raid Controller" } , + { 0x1103, 0x0005, "HPT372/372N", "PATA133 Raid Controller" } , + { 0x1103, 0x0006, "HPT302", "ATA Raid Controller" } , + { 0x1103, 0x0007, "HPT371", "ATA133 Controller" } , + { 0x1103, 0x0008, "HPT-374", "ATA Raid Controller" } , + { 0x1103, 0x1720, "RR172x", "RR172x SATA Controller" } , + { 0x1103, 0x1740, "RR174x", "RR174x SATA Controller" } , + { 0x1103, 0x1742, "RR174x", "RR174x SATA Controller" } , + { 0x1103, 0x2210, "RR2210", "RR2210 SATA Controller" } , + { 0x1103, 0x2300, "RR2300", "RR2300 SATA Controller" } , + { 0x1103, 0x2310, "RR231x", "RR231x SATA Controller" } , + { 0x1103, 0x2340, "RR2340", "RR2340 SATA Controller" } , + { 0x1103, 0x2522, "RR252x", "RR252x SATA Controller" } , + { 0x1103, 0x3120, "RR312x", "RR312x SATA Controller" } , + { 0x1103, 0x3220, "RR322x", "RR322x SATA Controller" } , + { 0x1103, 0x3320, "RR332x", "RR332x SATA Controller" } , + { 0x1103, 0x3410, "RR341x", "RR341x SATA Controller" } , + { 0x1103, 0x3510, "RR35xx", "RR35xx SATA Controller" } , + { 0x1103, 0x3511, "RR35xx", "RR35xx SATA Controller" } , + { 0x1103, 0x3520, "RR35xx", "RR35xx SATA Controller" } , + { 0x1103, 0x3521, "RR35xx", "RR35xx SATA Controller" } , + { 0x1103, 0x3522, "RR35xx", "RR35xx SATA Controller" } , + { 0x1103, 0x3540, "RR35xx", "RR35xx SATA Controller" } , + { 0x1103, 0x4320, "RR432x", "RR432x SATA Controller" } , + { 0x1103, 0x5081, "RR18xx", "RR18xx SATA Controller" } , + { 0x1103, 0x6081, "RR222x/224x", "RR222x/224x SATA Controller" } , + { 0x1103, 0x7042, "RR231x", "RR231x SATA Controller" } , + { 0x1681, 0x0050, "HWGPCI-54", "Hercules WiFi PCI 802.11G" } , + { 0x18F7, 0x0001, "ESCC-PCI-335", "Fastcom:ESCC-PCI-335 Syncronous RS422/485 serial communication adapter" } , + { 0x18F7, 0x0002, "422/4-PCI-335", "Fastcom:422/4-PCI-335 Asyncronous RS422/485 serial adapter" } , + { 0x18F7, 0x0004, "422/2-PCI-335", "Fastcom:422/2-PCI-335 Asyncronous RS422/485 serial adapter" } , + { 0x18F7, 0x000a, "232/4-PCI-335", "Fastcom:232/4-PCI-335 Asyncronous RS232 serial adapter" } , + { 0x1737, 0x1032, "EG1032 v3", "Linksys Instant Gigabit Desktop Network Interface" } , + { 0x19AC, 0x0001, "ACA2400", "Crypto Accelerator" } , + { 0x110A, 0x2101, "PEB 20321", "Multichannel Network Interface Controller for HDLC" } , + { 0x110A, 0x2102, "PEB 20534", "DMA supported serial communication controller with 4 channels" } , + { 0x110A, 0x3141, "01", "PROFIBUS Communication Processor CP5611 A2" } , + { 0x110A, 0x4033, "ERTEC400", "EB400 ProfiNet Device-Kit" } , + { 0x104B, 0x1040, "", "BT958 SCSI Host Adaptor" } , + { 0x104B, 0x8130, "-", "Flashpoint LT" } , + { 0x1180, 0x0475, "RL5c475", "Cardbus Controller" } , + { 0x1180, 0x0476, "unknown", "Ricoh R/RL/5C476(II)" } , + { 0x1180, 0x0478, "RB5c478", "Cardbus Controller" } , + { 0x1180, 0x0552, "R5C552", "FireWire (IEEE 1394) Controller" } , + { 0x1180, 0x0592, "13871043", "Ricoh Memory Stick Host Controller" } , + { 0x1180, 0x0822, "R5C832, R5C843", "SDA Standard Compliant SD Host Controller" } , + { 0x1180, 0x0832, "unknown", "IEEE 1394 (4 pin firewire) chip)" } , + { 0x1180, 0x0843, "R5C853", "Ricoh SD/MMC Host Controller" } , + { 0x1180, 0x0852, "01cf1028", "Ricoh xD-Picture Card Host Controller" } , + { 0x1180, 0x5551, "Unknown", "IEEE 1394 Controller" } , + { 0x14F1, 0x1035, "unknown", "unknown" } , + { 0x14F1, 0x1059, "DI15630-5, DI5631, DI5633", "SmartHCF" } , + { 0x14F1, 0x1456, "1456", "HCFp Modem" } , + { 0x14F1, 0x1611, "?", "AccessRunner ADSL Modem" } , + { 0x14F1, 0x2400, "unknown", "unknown" } , + { 0x14F1, 0x2702, "cx11252-15", "HSFp or Soft V92 Data Fax Modem" } , + { 0x14F1, 0x2BFA, "Unknown", "HDA D100 MDC v.92 Modem" } , + { 0x14F1, 0x2C06, "1002", "HDAUDIO Soft Data fax Modem with SmartPC" } , + { 0x14F1, 0x2F00, "00101767", "HSF 56k HSFi Modem" } , + { 0x14F1, 0x2F20, "CX11252-11", "HSFi PCI Internal Modem" } , + { 0x14F1, 0x2F30, "01", "Zyxel OMNI 56K PCI Plus Rev.3 " } , + { 0x14F1, 0x2F30, "01", "hp/compaq alhena 5-gl6" } , + { 0x14F1, 0x2F40, "71030277", "Conexant Modem RD02-D490" } , + { 0x14F1, 0x2F82, "cx9510-11z", "Conexant PCI-E Soft Data/Fax Modem with SmartCP" } , + { 0x14F1, 0x5045, "4.0.3.1", "HDAUDIO Soft Data fax Modem with SmartPC / Conexant High Definition SmartAudio HD2" } , +//# { 0x14F1, 0x50452, "1179FF31", "Conextant High Definition Audio-Venice 5045" } , + { 0x14F1, 0x5051, "4.0.1.6", "Audio" } , + { 0x14F1, 0x5051, "unknow", "Realtek High Definition audio" } , + { 0x14F1, 0x5051, "nForce 630M", "Conexant HD-Audio SmartAudio 221" } , + { 0x14F1, 0x5B7A, "Belived to be a CX23418", "Single-Chip MPEG-2 Encoder with Integrated Analog Video/Broadcast Audio Decoder" } , + { 0x14F1, 0x8800, "2003", "Conexant 23881 Video Capture (NTSC)" } , + { 0x14F1, 0x8852, "0x7717", "CX23881-21" } , + { 0x1971, 0x0001, "", "AGEIA PhysX 100 Series PCI Express Card" } , + { 0x1971, 0x1011, "PCIVEN_1971&DEV_1011&CC_FF00", "AGEIA PhysX 100 Series PCI Card" } , + { 0x1971, 0x1021, "", "AGEIA PhysX 200 Series PCI Express Card" } , + { 0x17C0, 0x12ab, "", "" } , + { 0x1682, 0x9875, "", "" } , + { 0x168C, 0x0007, "AR5005", "802.11a Wireless Adapter" } , + { 0x168C, 0x0011, "AR5bmb5", "802.11a Wireless Adapter" } , + { 0x168C, 0x0012, "AR5211", "802.11a/b/g Mini-PCI Wireless Adapter" } , + { 0x168C, 0x0013, "AR5212", "802.11a/b/g Wireless Adapter" } , + { 0x168C, 0x001A, "Atheros AR5005G", "Atheros AR5005G 802.11abg NIC Chipset / TP-Link (TL-WN551G)" } , + { 0x168C, 0x001B, "AR5006X", "802.11abg NIC" } , + { 0x168C, 0x001c, "VEN_10DE&DEV_0649&SUBSYS_059717FF&REV_A14&2DEFBOA", "HDAUDIOFUNC_01&VEN_10DE&DEV_0003&SUBSYS_10DE0101&REV_10004&6641A29&0&0201" } , + { 0x168C, 0x0023, "AR5416", "802.11a/b/g/n Wireless PCI Adapter" } , + { 0x168C, 0x0024, "AR5008", "Atheros 802.11a/b/g/n (pre-N) radio" } , + { 0x168C, 0x002A, "0001", "Atheros AR5B91 Wireless Network Adapter" } , + { 0x168C, 0x1014, "AR5212", "Atheros AR5212 802.11abg wireless" } , + { 0x168C, 0xFF96, "AR5212", "LAN-Express AS IEEE 802.11g miniPCI adapter" } , + { 0x1303, 0x0001, "0239", "cM67 CompactPCI DSP Card" } , + { 0x1303, 0x0002, "1", "M44/cM44 DSP board" } , + { 0x1303, 0x0003, "1", "Quattro6x DSP board" } , + { 0x1303, 0x0004, "1", "Chico/ChicoPlus Data Acquisition Board" } , + { 0x1303, 0x0005, "1", "Code Hammer Jtag Debugger board" } , + { 0x1303, 0x0006, "1", "Matador DSP board" } , + { 0x1303, 0x0007, "1", "Quixote DSP board" } , + { 0x1303, 0x0008, "1", "Quadia C64x DSP" } , + { 0x1303, 0x0009, "1", "Quadia DSP Baseboard" } , + { 0x4144, 0x0040, "ADM-XRC", "Virtex-E Bridge" } , + { 0x4144, 0x0041, "ADM-XRC-II Lite", "Virtex-II Bridge" } , + { 0x4144, 0x0042, "ADM-XRC-II", "Virtex-II Bridge" } , + { 0x4144, 0x0043, "ADM-XPL", "Virtex-II Pro Bridge" } , + { 0x4144, 0x0044, "ADM-XP", "Virtex-II Pro PCI/PCI-X Bridge" } , + { 0x4144, 0x0045, "ADP-WRC-II", "Virtex-II Bridge" } , + { 0x4144, 0x0046, "ADP-DRC-II", "Virtex-II Bridge" } , + { 0x4144, 0x0049, "ADP-XPI", "Virtex-II Pro PCI" } , + { 0x4144, 0x004A, "ADP-XPI (PCI-X)", "Virtex-II Pro PCI-X Bridge" } , + { 0x4144, 0x004F, "ADM-XRC-4FX", "Virtex-II Pro PCI-X Bridge" } , + { 0x4144, 0x0050, "ADM-XRC-5LX", "Virtex-4LX Bridge" } , + { 0x4144, 0x0051, "ADM-XRC-5T1", "ADM-XRC-5T1" } , + { 0x1332, 0x5410, "MM-5410D", "PCI 32bit Bulk Memory w/DMA" } , + { 0x1332, 0x5415, "MM-5415CN", "PCI Battery Backed SDRAM Adapter" } , + { 0x1332, 0x5425, "MM-5425CN", "PCI Memory Module with Battery Backup" } , + { 0x1332, 0x6140, "MM-6140D", "Memory Module" } , + { 0x1888, 0x0301, "", "" } , + { 0x1888, 0x0601, "", "" } , + { 0x1888, 0x0710, "", "" } , + { 0x1888, 0x0720, "", "" } , + { 0x1888, 0x2503, "Bt881", "Video Capture (10 bit High qualtiy cap)" } , + { 0x1888, 0x2504, "Bt878", "Video Capture" } , + { 0x1888, 0x3503, "nVidia NV28", "VGA Geforce4 MX440" } , + { 0x1888, 0x3505, "nVidia NV28", "VGA Geforce4 Ti4200" } , + { 0x167F, 0x4634, "", "FOB-IO Card" } , + { 0x167F, 0x4C32, "", "L2B PCI Board" } , + { 0x167F, 0x5344, "", "FOB-SD Card" } , + { 0x167F, 0x5443, "", "FOB-TDC Card" } , + { 0x14B5, 0x0200, "Scope", "" } , + { 0x14B5, 0x0300, "Pulsar", "" } , + { 0x14B5, 0x0400, "Pulsar SRB", "" } , + { 0x14B5, 0x0600, "Pulsar 2", "" } , + { 0x14B5, 0x0800, "", "DSP-Board" } , + { 0x14B5, 0x0900, "", "DSP-Board" } , + { 0x14B5, 0x0A00, "", "DSP-Board" } , + { 0x14B5, 0x0B00, "", "DSP-Board" } , + { 0x148C, 0x4011, "RV250", "RADEON 9000 PRO EVIL COMMANDO" } , + { 0x148C, 0x4152, "0x1002", "0x2079" } , + { 0x174B, 0x0260, "RV280", "Saphire Radeon 9250" } , + { 0x174B, 0x0261, "RV280", "Sapphire Radeon 9250 - Secondary" } , + { 0x174B, 0x7176, "RV250", "RADEON 9000 ATLANTIS PRO" } , + { 0x174B, 0x7177, "RV280", "RADEON 9000 ATLANTIS PRO - Secondary" } , + { 0x174B, 0x7C12, "RV280", "RADEON 9200 ATLANTIS - Secondary" } , + { 0x174B, 0x7C13, "RV280", "RADEON 9200 ATLANTIS" } , + { 0x174B, 0x9501, "RV670 ", "ATI Radeon HD 3870 " } , + { 0x17EE, 0x4153, "RV350", "Radeon 9550" } , + { 0x1328, 0x2048, "", "" } , + { 0x1328, 0x8888, "rev 1.5", "cPEG� C 3.0 DVD/MPEG2 decoder" } , + { 0x16EC, 0x0116, "RTL8169S", "RealTek 8169S chip" } , + { 0x16EC, 0x1007, "0637", "U.S. Robotics 56K Win INT" } , + { 0x16EC, 0x2013, "11323A", "U.S. Robotics 56K Voice Host Int" } , + { 0x16EC, 0x2F00, "USRobotics 5660A - Internal Soft Modem", "http://www.usr.com/support/product-template.asp?prod=5660a" } , + { 0x16EC, 0x2f12, "E129336-1", "U.S.Robotic (A- Modem/PCI)" } , + { 0x16EC, 0x3685, "???", "Wireless Access Adapter Model 022415" } , + { 0x16EC, 0x5685, "E129336-1", "U.S. Robotics 56K Voice Host Int (A-Modem/ PCI)" } , + { 0x003D, 0x00D1, "mx98715/25", "i740 PCI" } , + { 0x0E11, 0x0001, "", "PCI to EISA Bridge" } , + { 0x0E11, 0x0002, "ISA Bridge", " [URL=http://bjlsgpvs.com]zyqdruqt[/URL] pkooxpbn http://khmycdty.com znrqsyvm syeowswq " } , + { 0x13D0, 0x2200, "", "" } , + { 0x13D1, 0xAB02, "", "" } , + { 0x13D1, 0xAB03, "", "" } , + { 0x13D1, 0xAB06, "FE2000VX", "CardBus /Atelco Fibreline Ethernet Adptr" } , + { 0x13D1, 0xAB08, "SMC8035TX", "EZ Card� 10/100 Fast Ethernet CardBus Adapter" } , + { 0x13D7, 0x8086, "8086", "toshiba" } , + { 0x13D8, 0x1000, "XQ11800FP", "XaQti 1000Mbit/sec Gbit Ethernet Controller" } , + { 0x106B, 0x0001, "Bandit", "PowerPC Host-PCI Bridge" } , + { 0x106B, 0x0002, "Grand Central", "I/O Controller" } , + { 0x106B, 0x0003, "Control Video", "" } , + { 0x106B, 0x0004, "PlanB", "Video-in" } , + { 0x106B, 0x0007, "OHare", "I/O Controller" } , + { 0x106B, 0x000C, "", "" } , + { 0x106B, 0x000E, "Hydra", "Mac I/O Controller" } , + { 0x106B, 0x0010, "Heathrow", "Mac I/O Controller" } , + { 0x106B, 0x0017, "Paddington", "Mac I/O Controller" } , + { 0x106B, 0x0018, "UniNorth", "FireWire Controller" } , + { 0x106B, 0x001F, "UniNorth", "Host-PCI bridge" } , + { 0x106B, 0x0020, "UniNorth", "AGP interface" } , + { 0x106B, 0x0026, "Pangea", "USB Interface" } , + { 0x106B, 0x0027, "Pangea", "AGP interface" } , + { 0x106B, 0x002D, "UniNorth 1.5", "AGP Bridge" } , + { 0x106B, 0x002E, "UniNorth 1.5", "PCI Bridge" } , + { 0x106B, 0x002F, "UniNorth 1.5", "Internal PCI" } , + { 0x106B, 0x0030, "UniNorth/Pangea", "FireWire Controller" } , + { 0x106B, 0x003B, "Intrepid", "Integrated ATA Controller" } , + { 0x106B, 0x003F, "OHCI", "OHCI Controller" } , + { 0x106B, 0x004f, "Shasta", "Mac I/O controler" } , + { 0x106B, 0x0050, "Shasta", "IDE controler" } , + { 0x106B, 0x0051, "Shasta", "Sungem ethernet controler" } , + { 0x106B, 0x0052, "Shasta", "Firewire controler" } , + { 0x106B, 0x0053, "Shasta", "PCI Bridge" } , + { 0x106B, 0x0054, "Shasta", "PCI Bridge" } , + { 0x106B, 0x0055, "Shasta", "PCI Bridge" } , + { 0x106B, 0x0058, "U3L", "AGP Bridge" } , + { 0x106C, 0x8801, "", "Dual Pentium ISA/PCI Motherboard" } , + { 0x106C, 0x8802, "P54C Tr8", "PowerPC ISA/PCI Motherboard" } , + { 0x106C, 0x8803, "", "Dual Window Graphics Accelerator" } , + { 0x106C, 0x8804, "ht019a", "PCI LAN Controller" } , + { 0x106C, 0x8805, "", "100-BaseT LAN Controller" } , + { 0x106E, 0x4362, "88E8053", "Yukon PCI-E Gigabit Ethernet Controller (copper)" } , + { 0x1657, 0x0646, "BRE040", "Brocade 400 series PCIe HBA" } , + { 0x1073, 0x0001, "", "3D graphics Cntrlr" } , + { 0x1073, 0x0002, "YGV615", "RPA3 3D-Graphics Controller" } , + { 0x1073, 0x0003, "00011179", "" } , + { 0x1073, 0x0004, "YMF754B", "PCI Audio Controller" } , + { 0x1073, 0x0005, "DS1", "DS1 Audio" } , + { 0x1073, 0x0006, "DS1", "DS1 Audio" } , + { 0x1073, 0x0008, "DS1", "DS1 Audio" } , + { 0x1073, 0x000A, "YMF740", "DS-1L PCI Audio Controller" } , + { 0x1073, 0x000C, "YMF740C", "DS-1L PCI audio controller" } , + { 0x1073, 0x000D, "YMF724F", "Yamaha Onboard Sound System" } , + { 0x1073, 0x0010, "YMF744B-V", "DS-1 PCI audio controller" } , + { 0x1073, 0x0012, "YMF754B", "DS-1E PCI Audio Controller" } , + { 0x1073, 0x0020, "744", "DS-1 Audio" } , + { 0x1073, 0x1000, "SW1000XG", "Sound system" } , + { 0x1073, 0x2000, "DS2416", "Digital Mixing Card" } , + { 0x1074, 0x4E78, "82C500/1", "Nx586 Chipset" } , + { 0x1077, 0x1016, "ISP10160", "Single Channel Ultra3 SCSI Processor" } , + { 0x1077, 0x1020, "ISP1040B/1020A", "Fast-wide SCSI - Sparc PCI" } , + { 0x1077, 0x1022, "ISP1022A", "Fast-wide SCSI" } , + { 0x1077, 0x1080, "ISP1080", "SCSI Host Adapter" } , + { 0x1077, 0x1216, "ISP12160", "Dual Channel Ultra3 SCSI Processor" } , + { 0x1077, 0x1240, "ISP1240", "SCSI Host Adapter" } , + { 0x1077, 0x1280, "ISP1280", "SCSI Host Adapter" } , + { 0x1077, 0x2020, "ISP2020A", "Fast!SCSI Basic Adapter" } , + { 0x1077, 0x2100, "ISP2100", "64-bit Fibre Channel Adapter" } , + { 0x1077, 0x2200, "ISP2200", "PCI Fibre Channel Adapter" } , + { 0x1077, 0x2300, "ISP 2300", "64-bit PCI FC-AL Adapter" } , + { 0x1077, 0x2312, "ISP 2312", "Fibre Channel Adapter" } , + { 0x1077, 0x2422, "ISP2422", "QLogic PCI to Fibre Channel Host Adapter for QLA2460" } , + { 0x1077, 0x2432, "ISP2432", "Dual Channel 4G PCIe Fibre Channel Adapter" } , + { 0x1077, 0x3010, "n/a", "n/a" } , + { 0x1077, 0x4000, "", "" } , + { 0x1077, 0x4010, "", "" } , + { 0x1077, 0x6422, "EP2422", "4-Gbps Fibre Channel to PCI-X 2.0 266MHz controller for Embedded Applications" } , + { 0x1077, 0x6432, "EP2432", "4-Gbps Fibre Channel to PCIe controller for Embedded Applications" } , + { 0x1078, 0x0000, "Cx5520", "ISA Bridge" } , + { 0x1078, 0x0001, "MediaGXm", "Cyrix Integrated CPU" } , + { 0x1078, 0x0002, "Cx5520", "ISA Bridge" } , + { 0x1078, 0x0100, "Cx5530", "ISA bridge" } , + { 0x1078, 0x0101, "Cx5530", "SMI status and ACPI timer" } , + { 0x1078, 0x0102, "Cx5530", "IDE Controller" } , + { 0x1078, 0x0103, "Cx5530", "XpressAUDIO" } , + { 0x1078, 0x0104, "Cx5530", "Video Controller" } , + { 0x1078, 0x0400, "ZFMicro", "CPU to PCI Bridge" } , + { 0x1078, 0x0401, "ZFMicro", "Power Management Controller" } , + { 0x1078, 0x0402, "ZFMicro", "IDE Controller" } , + { 0x1078, 0x0403, "ZFMicro", "Expansion Bus" } , + { 0x1079, 0x0d01, "", "" } , + { 0x544C, 0x0350, "", "" } , + { 0x107D, 0x0000, "P86C850", "Graphic GLU-Logic" } , + { 0x107E, 0x0001, "FLIPPER", "FRED Local Bus I/F to PCI Peripheral" } , + { 0x107E, 0x0002, "", "100 vg anylan Cntrlr" } , + { 0x107E, 0x0004, "5526", "Fibre Channel Host Adapter" } , + { 0x107E, 0x0005, "x526", "Fibre Channel Host Adapter" } , + { 0x107E, 0x0008, "4575/5525/5575/6575", "(i)chipSAR+ 155 MBit ATM controller" } , + { 0x107E, 0x9003, "5535-4P-BRI-ST", "" } , + { 0x107E, 0x9007, "5535-4P-BRI-U", "" } , + { 0x107E, 0x9008, "5535-1P-SR", "" } , + { 0x107E, 0x900C, "5535-1P-SR-ST", "" } , + { 0x107E, 0x900E, "5535-1P-SR-U", "" } , + { 0x107E, 0x9011, "5535-1P-PRI", "" } , + { 0x107E, 0x9013, "5535-2P-PRI", "" } , + { 0x107E, 0x9023, "5535-4P-BRI-ST", "" } , + { 0x107E, 0x9027, "5536-4P-BRI-U", "" } , + { 0x107E, 0x9031, "5535-1P-PRI", "" } , + { 0x107E, 0x9033, "5536-2P-PRI", "Adapter" } , + { 0x107E, 0x9060, "6535", "CompactPCI T1/E1/J1Communications Ctrlr" } , + { 0x107E, 0x9070, "4538", "PMC T1/E1/J1 Communications Controller" } , + { 0x107E, 0x9080, "4532-002/005", "PMC ATM Over OC-3/STM-1 Comm Controller" } , + { 0x107E, 0x9081, "4532-001/004", "PMC ATM Over OC-3/STM-1 Comm Controller" } , + { 0x107E, 0x9082, "4532-000/003", "PMC ATM Over OC-3/STM-1 Comm Controller" } , + { 0x107E, 0x9090, "107", "PMC ATM Over T3/E3 Communications Ctrlr" } , + { 0x107E, 0x90A0, "4539", "PMC Quad T1/E1/J1 Communications Ctrlr" } , + { 0x107F, 0x0802, "SL82C105", "EIDE Ctrlr" } , + { 0x107F, 0x0803, "", "EIDE Bus Master Controller" } , + { 0x107F, 0x0806, "", "EIDE Controller" } , + { 0x107F, 0x2015, "", "EIDE Controller" } , + { 0x1080, 0x0600, "82C596/9", "CPU to PCI & PCI to ISA Bridge" } , + { 0x1080, 0xC691, "Cypress CY7c68001", "AN2131QC 0230" } , + { 0x1080, 0xC693, "82C693", "PCI to ISA Bridge" } , + { 0x1081, 0x0D47, "2330", "Radius PCI to NuBUS Bridge" } , + { 0x1083, 0x0001, "FR710", "PCI Enhanced IDE Adapter" } , + { 0x1083, 0x0613, "", "Host Bridge" } , + { 0x1085, 0x0001, "UsbDgn", "Datalaster Interface for OBD automotive" } , + { 0x1087, 0x9200, "", "" } , + { 0x108A, 0x0001, "Model 617", "PCI-VME Bus Adapter" } , + { 0x108A, 0x0010, "Model 618", "VME Bridge" } , + { 0x108A, 0x0040, "dataBLIZZARD", "" } , + { 0x108A, 0x3000, "Model 2106", "VME Bridge" } , + { 0x108D, 0x0001, "OC-3136/37", "Token-Ring 16/4 PCI Adapter" } , + { 0x108D, 0x0002, "OC-3139f", "Fastload 16/4 PCI/III Token Ring Adapter" } , + { 0x108D, 0x0004, "OC-3139/40", "RapidFire Token Ring 16/4 Adapter" } , + { 0x108D, 0x0005, "OC-3250", "GoCard Token Ring 16/4 Adapter" } , + { 0x108D, 0x0006, "OC-3530", "RapidFire Token Ring 100 Adapter" } , + { 0x108D, 0x0007, "OC-3141", "RapidFire Token Ring 16/4 Adapter" } , + { 0x108D, 0x0008, "OC-3540", "RapidFire HSTR 100/16/4 Adapter" } , + { 0x108D, 0x000A, "OC-3150", "RapidFire Token-Ring 16/4 PCI Adapter" } , + { 0x108D, 0x0011, "OC-2805", "Ethernet Controller" } , + { 0x108D, 0x0012, "OC-2325", "Ethernet PCI/II 10/100 Controller" } , + { 0x108D, 0x0013, "OC-2183/85", "PCI/II Ethernet Controller" } , + { 0x108D, 0x0014, "OC-2326", "Ethernet PCI/II 10/100 Controller" } , + { 0x108D, 0x0019, "OC-2327/50", "10/100 Ethernet Controller" } , + { 0x108D, 0x0021, "OC-6151/52", "155 Mbit ATM Adapter" } , + { 0x108D, 0x0022, "", "ATM Adapter" } , + { 0x108E, 0x0001, "SPARC EBUS", "" } , + { 0x108E, 0x1000, "PCIO", "PCI Input/Output Controller" } , + { 0x108E, 0x1001, "PCIO", "Happy Meal Ethernet" } , + { 0x108E, 0x1100, "RIO EBUS", "" } , + { 0x108E, 0x1101, "RIO GEM", "" } , + { 0x108E, 0x1102, "RIO 1394", "" } , + { 0x108E, 0x1103, "RIO USB", "" } , + { 0x108E, 0x2BAD, "GEM", "Sun Gigabit Ethernet Card" } , + { 0x108E, 0x5000, "SME2411", "UltraSPARC-IIi Advanced PCI Bridge" } , + { 0x108E, 0x5043, "SunPCI", "Co-processor" } , + { 0x108E, 0x7063, "SunPCi", "PCI card with Intel or AMD processor" } , + { 0x108E, 0x8000, "STP2223BGA", "UPA to PCI Interface (UPA)" } , + { 0x108E, 0x8001, "Schizo", "PCI Bus Module" } , + { 0x108E, 0xA000, "UltraSPARC IIi", "Sabre" } , + { 0x108E, 0xA001, "UltraSPARC IIe", "Hummingbird" } , + { 0x108E, 0xabba, "CE (Cassini Ethernet)", "10/100/1000 Ethernet adapter" } , + { 0x1091, 0x0020, "", "3D Graphics Processor" } , + { 0x1091, 0x0021, "", "3D graphics processor w/texturing" } , + { 0x1091, 0x0040, "", "3D graphics frame buffer" } , + { 0x1091, 0x0041, "", "3D graphics frame buffer" } , + { 0x1091, 0x0060, "", "Proprietary bus Bridge" } , + { 0x1091, 0x00E4, "Powerstorm 4D50T", "" } , + { 0x1091, 0x0720, "", "Motion JPEG Codec" } , + { 0x1092, 0x00A0, "SpeedStar Pro SE", "GUI Accelerator" } , + { 0x1092, 0x00A8, "SpeedStar 64", "GUI Accelerator" } , + { 0x1092, 0x0550, "Viper V550", "" } , + { 0x1092, 0x08D4, "Supra 2260", "WinModem" } , + { 0x1092, 0x094C, "SupraExpress 56i Pro", "SupraExpress 56i Pro" } , + { 0x1092, 0x09C8, "SUP2761", "SupraExpress 56i Pro VCC" } , + { 0x1092, 0x1002, "R6793-12", "RS56-pci" } , + { 0x1092, 0x1092, "Viper V330", "2710a" } , + { 0x1092, 0x6120, "Maximum", "DVD" } , + { 0x1092, 0x8810, "Stealth SE", "GUI Accelerator" } , + { 0x1092, 0x8811, "Stealth 64/SE", "GUI Accelerator" } , + { 0x1092, 0x8880, "Stealth Video", "" } , + { 0x1092, 0x8881, "Stealth Video", "GUI Accelerator" } , + { 0x1092, 0x88B0, "Stealth 64 Video", "GUI Accelerator" } , + { 0x1092, 0x88B1, "Stealth 64 Video", "GUI Accelerator" } , + { 0x1092, 0x88C0, "Stealth 64", "GUI Accelerator" } , + { 0x1092, 0x88C1, "Stealth 64", "GUI Accelerator" } , + { 0x1092, 0x88D0, "Stealth 64", "GUI Accelerator" } , + { 0x1092, 0x88D1, "Stealth 64", "GUI Accelerator" } , + { 0x1092, 0x88F0, "Stealth 64 Video", "GUI Accelerator" } , + { 0x1092, 0x88F1, "Stealth 64 Video", "GUI Accelerator" } , + { 0x1092, 0x9876, "", "Supra Express 56i Pro CW #2" } , + { 0x1092, 0x9999, "Monster Sound", "Diamand Technology DT0398" } , + { 0x1093, 0x0160, "PCI-DIO-96", "data adquisition input and output" } , + { 0x1093, 0x0161, "PCI-1200", "Multifunction data acquisition board" } , + { 0x1093, 0x0162, "PCI-MIO-16XE-50", "24MIO 6-03-2" } , + { 0x1093, 0x1150, "PCI-DIO-32HS", "High Speed Digital I/O Board" } , + { 0x1093, 0x1170, "PCI-MIO-16XE-10", "" } , + { 0x1093, 0x1180, "PCI-MIO-16E-1", "" } , + { 0x1093, 0x1190, "PCI-MIO-16E-4", "" } , + { 0x1093, 0x11B0, "", "" } , + { 0x1093, 0x11C0, "", "" } , + { 0x1093, 0x11D0, "", "" } , + { 0x1093, 0x11E0, "", "" } , + { 0x1093, 0x1270, "PCI-6032E", "Multifunction Data Acquisition Card" } , + { 0x1093, 0x12b0, "PCI-6534", "High Speed DIO" } , + { 0x1093, 0x1310, "PCI-6602", "Data Acquisition Device" } , + { 0x1093, 0x1320, "", "" } , + { 0x1093, 0x1330, "PCI-6031E", "" } , + { 0x1093, 0x1340, "PCI-6033E", "Multifunction Data Acquisition Card" } , + { 0x1093, 0x1350, "PCI-6071E", " NI PCI-6071E Multifunction I/O & NI-DAQ" } , + { 0x1093, 0x1360, "", "" } , + { 0x1093, 0x17D0, "PCI-6503", "" } , + { 0x1093, 0x18B0, "", "" } , + { 0x1093, 0x28b0, "NI 6014", "I/O Terminal NI-DAQ (Legacy) and NI-DAQmx" } , + { 0x1093, 0x2A60, "PCI-6023E", "" } , + { 0x1093, 0x2A70, "PCI-6024E", "Multifunction Data Acquisition Card" } , + { 0x1093, 0x2A80, "PCI-6025E", "Multifunction Data Acquisition Card" } , + { 0x1093, 0x2B20, "", "" } , + { 0x1093, 0x2C80, "PCI-6035E", "" } , + { 0x1093, 0x2CA0, "", "" } , + { 0x1093, 0x70af, "PCI-6221", "16-Bit, 250 kS/s, 16 Analog Inputs" } , + { 0x1093, 0x70b8, "NI PCI-6251", "Multifunction DAQ Device" } , + { 0x1093, 0xB001, "IMAQ-PCI-1408", "" } , + { 0x1093, 0xB011, "IMAQ-PXI-1408", "" } , + { 0x1093, 0xB021, "IMAQ-PCI-1424", "" } , + { 0x1093, 0xB031, "IMAQ-PCI-1413", "" } , + { 0x1093, 0xB041, "IMAQ-PCI-1407", "" } , + { 0x1093, 0xB051, "IMAQ-PXI-1407", "" } , + { 0x1093, 0xB061, "IMAQ-PCI-1411", "" } , + { 0x1093, 0xB071, "IMAQ-PCI-1422", "" } , + { 0x1093, 0xB081, "IMAQ-PXI-1422", "" } , + { 0x1093, 0xB091, "IMAQ-PXI-1411", "" } , + { 0x1093, 0xC801, "PCI-GPIB", "GPIB Controller Interface Board" } , + { 0x1093, 0xC811, "", "" } , + { 0x1093, 0xC821, "", "" } , + { 0x1093, 0xC831, "", "" } , + { 0x1093, 0xC840, "", "" } , + { 0x1093, 0xd130, "PCI-232/2", "2-port RS-232 Serial Interface Board" } , + { 0x1095, 0x0240, "SIL3112", "SATA/Raid controller(2XSATA150)" } , + { 0x1095, 0x0242, "SIL3132", "SATAII/Raid controller" } , + { 0x1095, 0x0244, "SIL3132", "eSATA/Raid controller" } , + { 0x1095, 0x0640, "PCI0640A/B", "EIDE Ctrlr" } , + { 0x1095, 0x0641, "PCI0640", "PCI EIDE Adapter with RAID 1" } , + { 0x1095, 0x0642, "PCI0642", "IDE Cntrlr w/RAID 1" } , + { 0x1095, 0x0643, "PCI0643", "PCI EIDE controller" } , + { 0x1095, 0x0646, "PCI0646", "bus master IDE" } , + { 0x1095, 0x0647, "PCI0647", "9738" } , + { 0x1095, 0x0648, "PCI-648", "Bus Master Ultra DMA PCI-IDE/ATA Chip" } , + { 0x1095, 0x0649, "PCI-649", "PATA100 RAID Controller" } , + { 0x1095, 0x0650, "PBC0650A", "Fast SCSI-II Ctrlr" } , + { 0x1095, 0x0670, "USB0670", "PCI-USB" } , + { 0x1095, 0x0673, "USB0673", "PCI-USB ASIC" } , + { 0x1095, 0x0680, "SiI 0680", "PATA133 Controller/RAID Controller" } , + { 0x1095, 0x1392, "1392", "INTEL HDMI AUDIO" } , + { 0x1095, 0x2455, "SI3124", "SATALink 4-Port PCI-X Host Controller" } , + { 0x1095, 0x3112, "SIL3112", "SATA/Raid controller(2XSATA150)" } , + { 0x1095, 0x3114, "Sil 3114", "SATALink/SATARaid Controller" } , + { 0x1095, 0x3124, "SiI 3124", "PCI-X to Serial ATA Controller" } , + { 0x1095, 0x3132, "SiI 3132", "PCI Express (1x) to 2 Port SATA300" } , + { 0x1095, 0x3512, "Sil 3512", "SATALink/SATARaid Controller" } , + { 0x1095, 0x3531, "3531", "SiI 3531 SATA Controller" } , + { 0x1096, 0x1106, "0x3059", "0x47204005&RE" } , + { 0x1097, 0x0038, "", "EIDE Controller (single FIFO)" } , + { 0x1098, 0x0001, "QD8500", "EIDE Controller" } , + { 0x1098, 0x0002, "QD8580", "EIDE Controller" } , + { 0x109A, 0x8280, "0x8280", "0x8280" } , + { 0x109E, 0x0350, "BT848KPF", "Bt848AKPF video decoder" } , + { 0x109E, 0x0350, "Bt878", "Multimedia Video Controller" } , + { 0x109E, 0x0351, "B t878 khf", "tc card" } , + { 0x109E, 0x0369, "Bt878fusion 878a", "Video Capture" } , + { 0x109E, 0x036C, "thık", "jfgj" } , + { 0x109E, 0x036E, "878Asad", "SVR-2000 V1.02" } , + { 0x109E, 0x036F, "Bt878", "Video Capturee" } , + { 0x109E, 0x0370, "Bt880", "Video Capture (10 bit High qualtiy cap)" } , + { 0x109E, 0x0878, "7610144D&REV_02\4&1F7DBC9F&0&09F0", "TV Video Capture" } , + { 0x109E, 0x0879, "Bt879khf", "Video Capture (Audio Section)" } , + { 0x109E, 0x0880, "Bt880", "Video Capture (Audio Section)" } , + { 0x109E, 0x109E, "Brooktree Corp BT848 SVR-2000 V1.02", "Multimedia Video Controller" } , + { 0x109E, 0x2115, "BtV 2115 Mera Lun", "BtV Mediastream Controller 9x" } , + { 0x109E, 0x2125, "BtV 2125", "BtV Mediastream Controller" } , + { 0x109E, 0x2164, "BtV 2164", "Display Adapter" } , + { 0x109E, 0x2165, "BtV 2165", "MediaStream Controller" } , + { 0x109E, 0x36e, "878a", "25878-13" } , + { 0x109E, 0x36E, "Bt360 MediaStream Controller", "Brooktree Corp" } , + { 0x109E, 0x36E, "CONEXANT FUSION 878A 25878-13 E349764.7", "conexant 878a" } , + { 0x109E, 0x8230, "BtV 8230", "ATM Segment/Reassembly Controller (SRC)" } , + { 0x109E, 0x8472, "Bt8471/72", "32/64-channel HDLC Controllers" } , + { 0x109E, 0x8474, "Bt8474", "128-channel HDLC Controller" } , + { 0x10A4, 0X5969, "", "" } , + { 0x9902, 0x0001, "SG2010", "PCI-to-PCI Bridge" } , + { 0x9902, 0x0002, "SG2010", "PCI to high speed serial bridge" } , + { 0x9902, 0x0003, "SG1010", "6 port serial switch /PCI-to-PCI bridge" } , + { 0x10A8, 0x0000, "?", "64-bit GUI Accelerator" } , + { 0x10A9, 0x0004, "O2 MACE", "" } , + { 0x10A9, 0x0005, "RAD Audio", "" } , + { 0x10A9, 0x0006, "HPCEX", "" } , + { 0x10A9, 0x0007, "RPCEX", "" } , + { 0x10A9, 0x0008, "DiVO VIP", "" } , + { 0x10A9, 0x0009, "Alteon", "Gigabit Ethernet" } , + { 0x10A9, 0x0010, "AMP", "Video I/O" } , + { 0x10A9, 0x0011, "GRIP", "" } , + { 0x10A9, 0x0012, "SGH PSHAC GSN", "" } , + { 0x10A9, 0x1001, "Magic Carpet", "" } , + { 0x10A9, 0x1002, "Lithium", "" } , + { 0x10A9, 0x1003, "Dual JPEG 1", "" } , + { 0x10A9, 0x1004, "Dual JPEG 2", "" } , + { 0x10A9, 0x1005, "Dual JPEG 3", "" } , + { 0x10A9, 0x1006, "Dual JPEG 4", "" } , + { 0x10A9, 0x1007, "Dual JPEG 5", "" } , + { 0x10A9, 0x1008, "Cesium", "" } , + { 0x10A9, 0x2001, "", "Fibre Channel" } , + { 0x10A9, 0x2002, "ASDE", "" } , + { 0x10A9, 0x8001, "O2 1394", "" } , + { 0x10A9, 0x8002, "G-net NT", "" } , + { 0x10AB, 0x1005, "USBVID_0000&PID_00005&5657949&0&8", "USB Bluetooth" } , + { 0x10AD, 0x0001, "W83769F", "EIDE Ctrlr" } , + { 0x10AD, 0x0103, "sl82c103", "PCI-ide mode 4.5 Cntrlr" } , + { 0x10AD, 0x0105, "W83789F", "Sonata bus master PCI-IDE controller" } , + { 0x10AD, 0x0565, "W83C553F", "PCI/ISA bridge" } , + { 0x10B5, 0x0324, "", "" } , + { 0x10B5, 0x0480, "IOP 480", "Integrated PowerPC I/O Processor" } , + { 0x10B5, 0x0960, "PCI 9080RDK-960", "PCI Reference Design Kit for PCI 9080" } , + { 0x10B5, 0x1030, "Gazel R685", "ISDN card" } , + { 0x10B5, 0x1054, "Gazel R697", "dual channel ISDN card" } , + { 0x10B5, 0x1078, "PCI 9050", "Vision Systems VScom PCI-210" } , + { 0x10B5, 0x1103, "PCI 9050", "Vision Systems VScom PCI-200" } , + { 0x10B5, 0x1146, "PCI 9050", "Vision Systems VScom PCI-010S" } , + { 0x10B5, 0x1147, "PCI 9050", "Vision Systems VScom PCI-020S" } , + { 0x10B5, 0x1151, "Gazel R753", "ISDN card" } , + { 0x10B5, 0x1152, "Gazel R753", "ISDN card" } , + { 0x10B5, 0x2724, "", "Thales PCSM Security Card" } , + { 0x10B5, 0x3001, "plx9030", "gpscard" } , + { 0x10B5, 0x5406, "PCI RDK9054-LITE", "PCI Reference Design Kit for PLX PCI 9054" } , + { 0x10B5, 0x5601, "PCI 9056", "32-bit; 66MHz PCI Bus Master I/O Accelerator, 17 x 17mm FPBGA" } , + { 0x10B5, 0x6520, "PCI6520", "PCI-X to PCI-X Bridge" } , + { 0x10B5, 0x8111, "PEX 8111, PEX 8311", "1 Lane PCI Express to PCI bridge (PEX8111); 1 Lane PCI Express to Generic Local Bus bridge (PEX8311)" } , + { 0x10B5, 0x8112, "PEX8112", "1 Lane PCI Express to PCI bridge" } , + { 0x10B5, 0x8509, "PEX8509", "8-lane PCI-Express Switch" } , + { 0x10B5, 0x8516, "PEX 8516", "Versatile PCI Express Switch" } , + { 0x10B5, 0x8518, "PEX8518-AB25BI", "PLX PCI-e switch" } , + { 0x10B5, 0x8532, "PEX 8532", "Versatile PCI Express Switch" } , + { 0x10B5, 0x8548, "8548", "48-lane PCIe switch" } , + { 0x10B5, 0x9030, "PCI 9030", "PCI SMARTarget I/O Accelerator" } , + { 0x10B5, 0x9036, "PCI9036", "Interface chip - value 1k" } , + { 0x10B5, 0x9050, "PCI 9050", "Target PCI Interface Chip - value 1k" } , + { 0x10B5, 0x9052, "PCI 9052", "PCI 9052 Target PLX PCI Interface Chip" } , + { 0x10B5, 0x9054, "PCI 9054", "PCI I/O Accelerator" } , + { 0x10B5, 0x9056, "PCI9056", "32-bit, 66 MHz PCI Bus-Mastering I/O Accelerator for PowerQUICC and Generic 32-bit, 66 MHz Local Bus" } , + { 0x10B5, 0x9060, "PCI9060", "PCI Bus Master Interface Chip" } , + { 0x10B5, 0x906D, "PCI 9060SD", "PCI Bus Master Interface Chip" } , + { 0x10B5, 0x906E, "PCI 9060ES", "PCI Bus Master Interface Chip" } , + { 0x10B5, 0x9080, "PCI 9080", "High performance PCI to Local Bus chip" } , + { 0x10B6, 0x0001, "Smart 16/4", "Ringnode (PCI1b)" } , + { 0x10B6, 0x0002, "Smart 16/4", "Ringnode (PCIBM2/CardBus)" } , + { 0x10B6, 0x0003, "Smart 16/4", "Ringnode" } , + { 0x10B6, 0x0004, "", "Smart 16/4 Ringnode Mk1 (PCIBM1)" } , + { 0x10B6, 0x0006, "", "16/4 CardBus Adapter (Eric 2)" } , + { 0x10B6, 0x0007, "Presto PCI", "" } , + { 0x10B6, 0x0009, "", "Smart 100/16/4 PCi-HS Ringnode" } , + { 0x10B6, 0x000A, "", "Smart 100/16/4 PCI Ringnode" } , + { 0x10B6, 0x000B, "", "16/4 CardBus Adapter Mk2" } , + { 0x10B6, 0x1000, "Horizon", "ATM adapter" } , + { 0x10B6, 0x1001, "Ambassador", "ATM adapter" } , + { 0x10B6, 0x1002, "Ambassador", "ATM Adapter" } , + { 0x10B7, 0x0001, "3C985", "1000BaseSX Gigabit Etherlink" } , + { 0x10B7, 0x0013, "3com p/n: 3CRDAG675", "3Com11a/b/g Wireless PCI Adapter " } , + { 0x10B7, 0x1000, "3C905CX-TXNM", "3COM 3C905CX-TXNM with 40-0664-003 ASIC" } , + { 0x10B7, 0x1006, "14e4:1645", "Broadcom Corporation NetXtreme BCM5701 Gigabit Ethernet" } , + { 0x10B7, 0x1007, "3C556", "V.90 Mini-PCI Modem" } , + { 0x10B7, 0x1700, "3C940", "Gigabit Ethernet PCI CODEC" } , + { 0x10B7, 0x1F1F, "3CRWE777A", "AirConnect Wireless LAN PCI Card" } , + { 0x10B7, 0x3390, "3C339", "Token Link Velocity" } , + { 0x10B7, 0x3590, "3C359", "TokenLink Velocity XL Adapter" } , + { 0x10B7, 0x4500, "3C450", "Cyclone" } , + { 0x10B7, 0x5055, "3C555", "Laptop Hurricane" } , + { 0x10B7, 0x5057, "3C575", "Megahertz 10/100 LAN CardBus PC Card" } , + { 0x10B7, 0x5157, "3C575B", "Megahertz 10/100 LAN CardBus PC Card" } , + { 0x10B7, 0x5257, "3CCFE575CT", "Cyclone Fast Ethernet CardBus PC Card" } , + { 0x10B7, 0x5900, "3C590", "Ethernet III Bus Fast PCI" } , + { 0x10B7, 0x5920, "3C592", "PCI/EISA 10Mbps Demon/Vortex" } , + { 0x10B7, 0x5950, "3C595", "Fast EtherLink PCI TX" } , + { 0x10B7, 0x5951, "3C595", "Fast EtherLink PCI T4" } , + { 0x10B7, 0x5952, "3C595", "Fast EtherLink PCI MII" } , + { 0x10B7, 0x5970, "3C597", "PCI/EISA Fast Demon/Vortex" } , + { 0x10B7, 0x5B57, "3C595", "Megahertz 10/100 LAN CardBus" } , + { 0x10B7, 0x6055, "3C556", "10/100 Fast Ethernet MiniPCI Adapter" } , + { 0x10B7, 0x6056, "3CN3AC1556B", "MiniPCI 10/100 Ethernet+Modem56k (see devid:1007)" } , + { 0x10B7, 0x6560, "3CCFE656", "Cyclone CardBus PC Card" } , + { 0x10B7, 0x6561, "FEM656", "10/100 LAN+56K Modem CardBus PC Card" } , + { 0x10B7, 0x6562, "3CCFEM656", "Cyclone CardBus PC Card" } , + { 0x10B7, 0x6563, "FEM656B", "10/100 LAN+56K Modem CardBus PC Card" } , + { 0x10B7, 0x6564, "3CCFEM656", "Cyclone CardBus PC Card" } , + { 0x10B7, 0x6565, "3CCFEM656C", "Global 10/100 Fast Ethernet+56K Modem" } , + { 0x10B7, 0x7646, "3CSOHO100B-TX", "Hurricane" } , + { 0x10B7, 0x7770, "???", "AirConnect Wireless PCI" } , + { 0x10B7, 0x8811, "", "Token Ring" } , + { 0x10B7, 0x9000, "3C900-TPO", "Fast Etherlink PCI TPO NIC" } , + { 0x10B7, 0x9001, "3C900-COMBO", "Fast Etherlink XL PCI Combo NIC" } , + { 0x10B7, 0x9004, "3C900-TPO", "EtherLink XL TPO 10Mb" } , + { 0x10B7, 0x9005, "3C900B-COMBO", "Fast Etherlink 10Mbps Combo NIC" } , + { 0x10B7, 0x9006, "3C900B-TPC", "EtherLink XL TPC" } , + { 0x10B7, 0x900A, "3C900B-FL", "EtherLink PCI Fiber NIC" } , + { 0x10B7, 0x9050, "3C905B - Combo", "Fast Etherlink XL PCI 10/100" } , + { 0x10B7, 0x9051, "3C905-T4", "Fast Etherlink XL 10/100" } , + { 0x10B7, 0x9055, "3C905-TX", "Fast Etherlink 10/100 PCI TX NIC" } , + { 0x10B7, 0x9056, "3C905B-T4", "Fast EtherLink XL 10/100" } , + { 0x10B7, 0x9058, "3C905B-COMBO", "Deluxe EtherLink 10/100 PCI Combo NIC" } , + { 0x10B7, 0x905A, "3C905B-FX", "Fast EtherLink 100 Fiber NIC" } , + { 0x10B7, 0x9200, "3C905 CX-TX-M", "Fast EtherLink for PC Management NIC" } , + { 0x10B7, 0x9201, "3C920B-EMB", "Integrated Fast Ethernet Controller" } , + { 0x10B7, 0x9202, "3C920B-EMB", "3C920B-EMB 3Com + Realtek 8201L" } , + { 0x10B7, 0x9210, "3C920B-EMB-WNM", "Integrated Fast Ethernet Controller" } , + { 0x10B7, 0x9300, "3csoho100b-tx", "3ComSOHO100B-TX" } , + { 0x10B7, 0x9800, "3C980-TX", "Fast EtherLink XL Server Adapter2" } , + { 0x10B7, 0x9805, "3C980-TX", "Python-T 10/100baseTX NIC" } , + { 0x10B7, 0x9902, "3CR990-TX-95", "EtherLink 10/100 PCI with 3XP Processor" } , + { 0x10B7, 0x9903, "3CR990-TX-97", "EtherLink 10/100 PCI with 3XP Processor" } , + { 0x10B7, 0x9905, "3C990B-FX", "100FX PCI Server NIC w/3XP" } , + { 0x10B7, 0x9908, "3CR990SVR95", "EtherLink 10/100 Server PCI with 3XP" } , + { 0x10B7, 0x9909, "3CR990SVR97", "EtherLink 10/100 Server PCI with 3XP" } , + { 0x10B7, 0xD004, "3C900B-TPO", "EtherLink XL PCI" } , + { 0x10B8, 0x0005, "LAN83C170QF/171", "EPIC/XF 10/100 Mbps Fast Ethernet Ctrlr" } , + { 0x10B8, 0x0006, "LAN83C175", "EPIC/C Ethernet CardBus Integrated Ctrlr" } , + { 0x10B8, 0x1000, "37C665", "FDC" } , + { 0x10B8, 0x1001, "37C922", "FDC" } , + { 0x10B8, 0xA011, "83C170QF", "Fast ethernet controller" } , + { 0x10B8, 0xB106, "SMC34C90", "CardBus Controller" } , + { 0x10B9, 0x0101, "CMI8338/C3DX", "PCI Audio Device (OEM)" } , + { 0x10B9, 0x0102, "CMI8338/C3DX", "PCI Audio Device (OEM)" } , + { 0x10B9, 0x0111, "CMI8738/C3DX", "C-Media Audio Device (OEM)" } , + { 0x10B9, 0x0780, "???", "Multi-IO Card" } , + { 0x10B9, 0x0782, "???", "Multi-IO Card" } , + { 0x10B9, 0x10b9, "ALI M5273 A1", "0539 TS05 CKB42321000B" } , + { 0x10B9, 0x1435, "M1435", "VL Bridge" } , + { 0x10B9, 0x1445, "M1445", "CPU to PCI & PCI to ISA Bridge w/EIDE" } , + { 0x10B9, 0x1449, "M1449", "ISA Bridge" } , + { 0x10B9, 0x1451, "M1451", "Pentium CPU to PCI Bridge" } , + { 0x10B9, 0x1461, "M1461", "P54C Chipset" } , + { 0x10B9, 0x1489, "M1489", "486 PCI Chipset" } , + { 0x10B9, 0x1511, "M1511", "Aladdin 2 Host Bridge" } , + { 0x10B9, 0x1513, "M1513", "Aladdin 2 South Bridge" } , + { 0x10B9, 0x1521, "M1521", "Bios" } , + { 0x10B9, 0x1523, "M1523", "ISA Bridge" } , + { 0x10B9, 0x1533, "M1535+", "PCI South Bridge" } , + { 0x10B9, 0x1535, "M1535x", "ISA Bridge" } , + { 0x10B9, 0x1541, "M1541", "Aladdin V AGPset Host Bridge" } , + { 0x10B9, 0x1543, "M1543 a1", "Aladdin V chipset South Bridge" } , + { 0x10B9, 0x1561, "M1561", "North Bridge" } , + { 0x10B9, 0x1563, "M1563", "South Bridge with Hypertransport Support" } , + { 0x10B9, 0x1632, "M1632", "North Bridge" } , + { 0x10B9, 0x1641, "M1641", "CPU to PCI Bridge" } , + { 0x10B9, 0x1644, "M1644", "AGP System Controller" } , + { 0x10B9, 0x1646, "M1646", "AGP System Controller" } , + { 0x10B9, 0x1647, "M1647", "CPU to PCI Bridge" } , + { 0x10B9, 0x1651, "M1651", "CPU to PCI Bridge" } , + { 0x10B9, 0x1661, "M1661", "AGP System Controller" } , + { 0x10B9, 0x1667, "M1667", "AGP System Controller" } , + { 0x10B9, 0x1671, "M1671", "Super P4 Nouth Bridge" } , + { 0x10B9, 0x1672, "M1672", "AGP System Controller" } , + { 0x10B9, 0x1681, "M1681", "P4 Nouth Bridge with HyperTransport" } , + { 0x10B9, 0x1687, "M1687", "K8 North Bridge with HyperTransport" } , + { 0x10B9, 0x3141, "M3141", "GUI Accelerator" } , + { 0x10B9, 0x3143, "M3143", "GUI Accelerator" } , + { 0x10B9, 0x3145, "M3145", "GUI Accelerator" } , + { 0x10B9, 0x3147, "M3147", "GUI Accelerator" } , + { 0x10B9, 0x3149, "M3149", "GUI Accelerator" } , + { 0x10B9, 0x3151, "M3151", "GUI Accelerator" } , + { 0x10B9, 0x3307, "M3307", "MPEG-1 Decoder" } , + { 0x10B9, 0x3309, "M3309", "MPEG Decoder" } , + { 0x10B9, 0x5212, "M4803", "" } , + { 0x10B9, 0x5215, "MS4803", "EIDE Ctrlr" } , + { 0x10B9, 0x5217, "m5217h", "I/O (?)" } , + { 0x10B9, 0x5219, "?", "Ali M5219 PCI BUS MASTER IDE Controller" } , + { 0x10B9, 0x5225, "M5225", "IDE Controller" } , + { 0x10B9, 0x5228, "M1563", "M5228 PATA/RAID Controller" } , + { 0x10B9, 0x5229, "M5229 Southbridge", "EIDE Controller" } , + { 0x10B9, 0x5229, "?", "Ali EIDE" } , + { 0x10B9, 0x5229, "?", "PATA 33" } , + { 0x10B9, 0x5229, "?", "PATA 66" } , + { 0x10B9, 0x5229, "?", "PATA 100" } , + { 0x10B9, 0x5229, "?", "PATA 133" } , + { 0x10B9, 0x5235, "M1621", "I/O Controller" } , + { 0x10B9, 0x5236, "M5273", "EHCI USB 2.0" } , + { 0x10B9, 0x5237, "M5273 A1 for windows 98", "OpenHCI 1.1 USB to 2.0" } , + { 0x10B9, 0x5239, "527210B9", "USB EHCI2.0 Controller" } , + { 0x10B9, 0x5249, "M5249", "HyperTransport to PCI Bridge" } , + { 0x10B9, 0x5251, "M5251", "IEEE P1394 OpenHCI 1.0 Controller" } , + { 0x10B9, 0x5253, "M5253", "IEEE P1394 OpenHCI 1.0 Controller" } , + { 0x10B9, 0x5261, "M5261", "Ethernet Controller" } , + { 0x10B9, 0x5263, "Albatron K8ULTRA-U Pro", "ULi PCI Fast Ethernet Controller" } , + { 0x10B9, 0x5281, "M1565/1566", "ALI M5281/5283 SATA/RAID Controller" } , + { 0x10B9, 0x5287, "ULI M1573", "SATA/Raid controller" } , + { 0x10B9, 0x5288, "ULI M1575/M1697 ", "M5288 SATA/Raid controller" } , + { 0x10B9, 0x5289, "ULI M1567/M1689 ", "M5289 SATA/Raid controller" } , + { 0x10B9, 0x5450, "65525", "Agere Systems AC97 Modem" } , + { 0x10B9, 0x5451, "M5451", "Ali Audio Accelerator" } , + { 0x10B9, 0x5455, "M1563M Southbridge", "AC'97 Audio Controller" } , + { 0x10B9, 0x5457, "M1563M", "AC97 Modem controller" } , + { 0x10B9, 0X5459, "MDV92XP NetoDragon", "PCI Soft Modem V92 NetoDragon" } , + { 0x10B9, 0x5461, "M5461", "High Definition Audio Controller" } , + { 0x10B9, 0x5471, "M1563M Southbridge", "Memory Stick Host" } , + { 0x10B9, 0x5473, "M1563M Southbridge", "MMC/SD controller" } , + { 0x10B9, 0x7101, "M7101", "Power Management Controller" } , + { 0x10B9, 0x7471, "M1563M Southbridge", "Memory Stick Host" } , + { 0x10B9, 0x9876, "mdv92xp", "xhcth700000b" } , + { 0x10BA, 0x0304, "", "GUI Accelerator" } , + { 0x10BD, 0x0803, " MYSON Technology Inc SURECOM EP-320X-S 100/10M Et", "Ethernet PCI Adapter" } , + { 0x10BD, 0x0E34, "NE34", "Ethernet Adapter (NE2000 PCI clone)" } , + { 0x10BD, 0x5240, "0055", "IDE Cntrlr" } , + { 0x10BD, 0x5241, "", "PCMCIA Bridge" } , + { 0x10BD, 0x5242, "", "General Purpose Cntrlr" } , + { 0x10BD, 0x5243, "00000000", "Bus Cntrlr" } , + { 0x10BD, 0x5244, "", "FCD Cntrlr" } , + { 0x10BD, 0x8139, "surecom EP-320X-R adapter with realtek 8139c chip", "realtek 8139c" } , + { 0x10C3, 0x8920, "5335fn800829", "" } , + { 0x10C3, 0x8925, "", "" } , + { 0x10C4, 0x8363, "s/n124102160", "pci pnp686" } , + { 0x10C8, 0x0004, "", "" } , + { 0x10C8, 0x0000, "", "Graphics Cntrlr" } , + { 0x10C8, 0x0003, "NM2093", "MagicGraph 128ZV Video Controller" } , + { 0x10C8, 0x0004, "NM2160", "MagicGraph 128XD" } , + { 0x10C8, 0x0005, "NM2200", "MagicMedia 256AV" } , + { 0x10C8, 0x0006, "NM2360", "MagicMedia 256ZX/256M6D" } , + { 0x10C8, 0x0016, "NM2380", "MagicMedia 256XL+" } , + { 0x10C8, 0x0025, "NM2230", "MagicMedia 256AV+" } , + { 0x10C8, 0x0083, "NM2097", "Graphic Controller NeoMagic MagicGraph128ZV+" } , + { 0x10C8, 0x8005, "NM2200", "MagicMedia 256AV Audio Device" } , + { 0x10C8, 0x8006, "NM2360", "MagicMedia 256ZX Audio Device" } , + { 0x10C8, 0x8016, "NM2380", "MagicMedia 256XL+ Audio Device" } , + { 0x10CD, 0x1100, "ASC1100", "PCI SCSI Host Adapter" } , + { 0x10CD, 0x1200, "ASC1200", "Fast SCSI-II" } , + { 0x10CD, 0x1300, "ASC-3550b", "ASC-3550b" } , + { 0x10CD, 0x2300, "F914C536", "PCI Ultra Wide SCSI Host Adapter" } , + { 0x10CD, 0x2500, "ASC38C0800/1600", "PCI Ultra 80/160 SCSI Controllers" } , + { 0x10CD, 0x4000, "ASC30C0400", "IEEE-1394 OHCI PCI Controller" } , + { 0x10CF, 0x10C5, "FMV-103", "Serial Parallel Card" } , + { 0x10CF, 0x2001, "MB86605", "PCI SCSI Host Adapter (Fast Wide SCSI-2)" } , + { 0x10CF, 0x2002, "MB86606", "Fast Wide SCSI Controller" } , + { 0x10CF, 0x2005, "MB86974", "10/100 Fast Ethernet Adapter" } , + { 0x10CF, 0x200C, "MB86974", "IEEE1394 OpenHCI Controller" } , + { 0x10CF, 0x2010, "", "OHCI FireWire Controller" } , + { 0x10CF, 0x2011, "", "MPEG2 R-Engine (MPEG2 Hardware Encoder)" } , + { 0x10CF, 0x2019, "MB86295", "Coral-P Graphics Chip" } , + { 0x10CF, 0x201E, "MB86296", "Coral-PA Graphics Chip" } , + { 0x10D6, 0xFF51, "0x0100", "C87899D" } , + { 0x10D6, 0xff66, "0x0100", "C87899D" } , + { 0x1658, 0x0704, "905410B5", "DIG 704 PCI - Interface with Millisecond Timer and Interrupts" } , + { 0x10D9, 0x0066, "MX86101P", "sdas" } , + { 0x10D9, 0x0512, "MX98713", "Fast Ethernet Adapter" } , + { 0x10D9, 0x0531, "MX98715/25", "Single Chip Fast Ethernet NIC Controller" } , + { 0x10D9, 0x0532, "MX98723/727", "PCI/CardBus Fast Ethernet Controller" } , + { 0x10D9, 0x0553, "MX987x5", "Ethernet Adapter" } , + { 0x10D9, 0x8625, "MX86250", "xiankasqudong" } , + { 0x10D9, 0x8626, "MX86251", "" } , + { 0x10D9, 0x8627, "MX86251", "" } , + { 0x10D9, 0x8888, "MX86250", "9619E" } , + { 0x10D9, 0xC115, "lc82c115", "" } , + { 0x10DC, 0x0001, "STAR/RD24", "PCI-SCI PMC mezzanine" } , + { 0x10DC, 0x0002, "ATT 2C15-3 (FPGA)", "SCI bridge on PCI 5 Volt card" } , + { 0x10DC, 0x0004, "EP20S780", "ALTERA STRATIX" } , + { 0x10DC, 0x0010, "680-1110-150/400", "Simple PMC/PCI to S-LINK interface" } , + { 0x10DC, 0x0011, "680-1110-200/450", "Simple S-LINK to PMC/PCI interface" } , + { 0x10DC, 0x0012, "S32PCI64", "32-bit S-LINK to 64-bit PCI interface" } , + { 0x10DC, 0x0021, "", "HIPPI destination" } , + { 0x10DC, 0x0022, "", "HIPPI source" } , + { 0x10DC, 0x0033, "EP20KE (APEX-FPGA)", "ALICE DDL to PCI interface (RORC)" } , + { 0x10DC, 0x0101, "SL651 7057 C200", "Acquisition card for the SPS Orbit System (MACI)" } , + { 0x10DC, 0x016A, "XC4VFX100", "CALICE ODR" } , + { 0x10DC, 0x10DC, "ATT 2C15-3 (FPGA)", "TTC sr first TTC chip receiver PMC" } , + { 0x10DC, 0x301, "PLX PCI 9030", "based on the PLX PCI 9030 to build a MIL1553 bus interface" } , + { 0x10DC, 0x324, "PLX PCI96556", "64 Bit/66MHz PCI to Local Bus Bridge" } , + { 0x10DD, 0x0001, "", "3D graphics processor" } , + { 0x10DE, 0x04EF, "NV3", "Riva 128" } , + { 0x10DE, 0x0001, "Lucent 0x00da", "SoundMAX Integrated Digital Audio" } , + { 0x10DE, 0x0003, "It seems to be Realtek ALC888/9", "nVIDIA High Definition Audio/HDMI " } , + { 0x10DE, 0x0008, "NV1", "Edge 3D" } , + { 0x10DE, 0x0009, "NV1", "Edge 3D" } , + { 0x10DE, 0x0010, "NV2", "Mutara V08" } , + { 0x10DE, 0x0018, "NV3", "Riva 128" } , + { 0x10DE, 0x0019, "NV3", "Riva 128ZX" } , + { 0x10DE, 0x0020, "NV4", "Riva TNT" } , + { 0x10DE, 0x0028, "NV5", "TNT2 / TNT2 Pro" } , + { 0x10DE, 0x0029, "NV5", "TNT2 Ultra" } , + { 0x10DE, 0x002A, "NV5", "TNT2" } , + { 0x10DE, 0x002B, "NV5", "Riva TNT2" } , + { 0x10DE, 0x002C, "8.0", "Vanta/Vanta LT" } , + { 0x10DE, 0x002D, "NV5", "TNT2 Model 64 / TNT2 Model 64 Pro" } , + { 0x10DE, 0x002E, "NV6", "VANTA" } , + { 0x10DE, 0x002F, "NV6", "VANTA" } , + { 0x10DE, 0x0035, "MCP04", "MCP04 PATA Controller" } , + { 0x10DE, 0x0036, "MCP04", "MCP04 SATA/RAID Controller" } , + { 0x10DE, 0x003E, "MCP04", "MCP04 SATA/RAID Controller" } , + { 0x10DE, 0x0040, "NV40.0", "GeForce 6800 Ultra" } , + { 0x10DE, 0x0041, "NV40.1", "GeForce 6800" } , + { 0x10DE, 0x0042, "NV40.2", "Geforce 6800LE" } , + { 0x10DE, 0x0043, "NV40.3", "nforce3 250" } , + { 0x10DE, 0x0045, "NV40.5", "GeForce 6800 GT" } , + { 0x10DE, 0x0049, "NV40GL", "???" } , + { 0x10DE, 0x004E, "NV40GL", "Quadro FX 4000" } , + { 0x10DE, 0x0053, "CK804", "CK804 PATA Controller" } , + { 0x10DE, 0x0054, "CK804", "CK804 SATA/RAID Controller" } , + { 0x10DE, 0x0055, "CK804", "CK804 SATA/RAID Controller" } , + { 0x10DE, 0x0057, "nForce4 Ultra", "NVidia Network Bus Enumerator Description du p�riph�rique nVIDIA nForce4 SLI (CK8-04) - LAN Controll" } , + { 0x10DE, 0x0059, "Realtek ALC850", "Realtek AC'97 Audio" } , + { 0x10DE, 0x0060, "nForce MCP2", "ISA Bridge" } , + { 0x10DE, 0x0064, "nForce MCP-T", "SMBus Controller" } , + { 0x10DE, 0x0065, "nForce MCP2/MCP2-T/MCP2-U", "PATA Controller" } , + { 0x10DE, 0x0066, "nForce MCP-T", "Ethernet Adapter Chip 10/100/HD/FD-Autosense" } , + { 0x10DE, 0x0067, "nForce MCP2", "OpenHCI USB Controller" } , + { 0x10DE, 0x0068, "nForce MCP2", "EHCI USB 2.0 Controller" } , + { 0x10DE, 0x006A, "nForce MCP2", "Audio Codec Interface" } , + { 0x10DE, 0x006B, "nForce MCP-T?", "Audio Processing Unit (Dolby Digital)" } , + { 0x10DE, 0x006C, "nForce", "PCI to PCI Bridge" } , + { 0x10DE, 0x006D, "nForce MCP-T", "Audio Codec Interface" } , + { 0x10DE, 0x006E, "nForce MCP2", "OHCI Compliant IEEE 1394 Controller" } , + { 0x10DE, 0x0085, "MCP2S", "MCP2S PATA Controller" } , + { 0x10DE, 0x008C, "RLT8201BL", "Single-Port 10/100M Fast Ethernet PHYceiver" } , + { 0x10DE, 0x008E, "MCP2S", "MCP2S SATA/RAID Controller" } , + { 0x10DE, 0x0091, "G70", "GeForce 7800 GTX" } , + { 0x10DE, 0x0092, "NV47 (20x1,7vp)", "GeForce 7800GT" } , + { 0x10DE, 0x009C, "G70.1", "Quadro FX 350M" } , + { 0x10DE, 0x009D, "?", "NVIDIA GPU Quadro FX 4500" } , + { 0x10DE, 0x00A0, "NV5", "Aladdin TNT2" } , + { 0x10DE, 0x00C0, "NV41.0", "NV41GS" } , + { 0x10DE, 0x00C1, "NV41.1", "NVIDIA GeForce 6800" } , + { 0x10DE, 0x00C2, "NV41.2", "???" } , + { 0x10DE, 0x00C8, "NV41", "GeForce FX 6800 Go" } , + { 0x10DE, 0x00C9, "NV41", "GeForce FX 6800 Ultra Go" } , + { 0x10DE, 0x00CC, "NV41", "Quadro FX 1400 Go" } , + { 0x10DE, 0x00CD, "NV41GL", "Quadro FX 3450/4000 SDI" } , + { 0x10DE, 0x00CE, "NV41GL", "NVIDIA Quadro FX1400" } , + { 0x10DE, 0x00D0, "nForce 3", "LPC Bridge" } , + { 0x10DE, 0x00D1, "nForce 3", "Host Bridge" } , + { 0x10DE, 0x00D2, "nForce 3?", "PCI-to-PCI Bridge" } , + { 0x10DE, 0x00D4, "nForce MCp2", "SMBus Controller" } , + { 0x10DE, 0x00D5, "nForce3-150", "CK8 PATA 133/PATA to SATA Bridge" } , + { 0x10DE, 0x00D6, "nForce MCP3?", "Networking Controller" } , + { 0x10DE, 0x00D7, "nForce MCP3?", "OpenHCD USB Host Controller" } , + { 0x10DE, 0x00D8, "nForce MCP3?", "Enhanced PCI to USB Host Controller" } , + { 0x10DE, 0x00D9, "nForce 3", "Agere System PCI Soft Modem" } , + { 0x10DE, 0x00DA, "Lucent", "SoundMAX Integrated Digital Audio" } , + { 0x10DE, 0x00DD, "nForce MCP3?", "PCI-to-PCI Bridge" } , + { 0x10DE, 0x00DF, "Marvell 88E1111", "Network adapter" } , + { 0x10DE, 0x00E0, "nForce3 250", "LPC Interface Bridge" } , + { 0x10DE, 0x00E1, "nForce3 250", "Host/PCI Bridge" } , + { 0x10DE, 0x00E2, "nForce3 250", "AGP Host to PCI Bridge" } , + { 0x10DE, 0x00E3, "nForce 250", "CK8S SATA/RAID Controller" } , + { 0x10DE, 0x00E4, "nForce3 250", "PCI System Management" } , + { 0x10DE, 0x00E5, "nForce3 250", "Parallel ATA Controller" } , + { 0x10DE, 0x00E7, "nForce3 250", "OpenHCD USB Controller" } , + { 0x10DE, 0x00E8, "nForce3 250", "Enhanced PCI to USB Controller" } , + { 0x10DE, 0x00EA, "nForce3 250", "Audio Codec Interface" } , + { 0x10DE, 0x00ED, "nForce3 250", "PCI-PCI Bridge" } , + { 0x10DE, 0x00EE, "nForce 250", "CK8S SATA/RAID Controller" } , + { 0x10DE, 0x00F0, "NVBR02", "???" } , + { 0x10DE, 0x00F1, "NV43+BR02", "GeForce 6600 GT AGP" } , + { 0x10DE, 0x00F2, "NV43", "GeForce 6600" } , + { 0x10DE, 0x00F5, "G70", "GeForce 7800 GS" } , + { 0x10DE, 0x00F6, "NV41", "Geforce 6800GS" } , + { 0x10DE, 0x00F8, "NVBR02", "NVIDIA Quadro FX 3400/4400" } , + { 0x10DE, 0x00F9, "NVBR02", "GeForce 6800 GTO" } , + { 0x10DE, 0x00FA, "NVBR02.2", "GeForce PCX 5750" } , + { 0x10DE, 0x00FB, "NVBR02.3", "GeForce PCX 5900" } , + { 0x10DE, 0x00FC, "NVBR02.4", "GeForce PCX 5300" } , + { 0x10DE, 0x00FD, "NVBR02GL", "Quadro NVS 280 PCI-E" } , + { 0x10DE, 0x00FE, "NVBR02GL", "Quadro FX 1300" } , + { 0x10DE, 0x00FF, "NVBR02.7", "GeForce PCX 4300" } , + { 0x10DE, 0x0100, "NV10", "GeForce 256" } , + { 0x10DE, 0x0101, "NV10", "GeForce 256 DDR" } , + { 0x10DE, 0x0102, "NV10", "GeForce 256 Ultra" } , + { 0x10DE, 0x0103, "NV10GL", "Quadro (GeForce 256 GL)" } , + { 0x10DE, 0x0110, "NV11", "GeForce2 MX / MX 400" } , + { 0x10DE, 0x0111, "NV11DDR", "GeForce2 MX 100/200� (DDR)" } , + { 0x10DE, 0x0112, "NV11", "GeForce2 Go / MX Ultra" } , + { 0x10DE, 0x0112, "???", "Nvidia GeForce2 Go/MX Ultra Video Adapter" } , + { 0x10DE, 0x0113, "NV11GL", "Quadro2 MXR / EX / Go" } , + { 0x10DE, 0x0141, "NV43", "NVIDIA GeForce 6600" } , + { 0x10DE, 0x0145, "NV43", "NVIDIA GeForce 6610 XL" } , + { 0x10DE, 0x0148, "unknown", "GeForce Go 6600" } , + { 0x10DE, 0x014D, "unknown", "NVIDIA Quadro FX 5500" } , + { 0x10DE, 0x014E, "NV43", "NVIDIA Quadro FX 540" } , + { 0x10DE, 0x014F, "NV43", "NVIDIA GeForce 6200" } , + { 0x10DE, 0x0150, "NV15", "GeForce2 GTS / Pro" } , + { 0x10DE, 0x0151, "NV15 DDR", "GeForce2 Ti" } , + { 0x10DE, 0x0152, "NV15BR", "GeForce2 Ultra (BladeRunner)" } , + { 0x10DE, 0x0153, "NV15GL", "Quadro2 Pro" } , + { 0x10DE, 0x0160, "NV44 (Code Name)", "GPU 6500 " } , + { 0x10DE, 0x0162, "NV44?", "GeForce 6200SE TurboCache" } , + { 0x10DE, 0x0163, "00", "Geforce 6200 LE" } , + { 0x10DE, 0x0164, "NV44?", "GeForce FX 6200 Go" } , + { 0x10DE, 0x0165, "NVS285", "Quadro NVS 285" } , + { 0x10DE, 0x016a, "NVidia GeForce 7100 GS", "VGA" } , + { 0x10DE, 0x0170, "NV17.2", "GeForce4 MX 460" } , + { 0x10DE, 0x0171, "NV17.2", "GeForce4 MX 440" } , + { 0x10DE, 0x0172, "NV17.3", "GeForce4 MX 420" } , + { 0x10DE, 0x0173, "NV17.4", "GeForce4 MX 440-SE" } , + { 0x10DE, 0x0174, "NV17M", "GeForce4 440 Go 64MB" } , + { 0x10DE, 0x0175, "NV17M", "GeForce4 420 Go" } , + { 0x10DE, 0x0176, "NV17M", "GeForce4 420 Go 32M" } , + { 0x10DE, 0x0177, "NV17M", "GeForce4 460 Go" } , + { 0x10DE, 0x0178, "NV17GL.1", "Quadro4 500/550 XGL" } , + { 0x10DE, 0x0179, "NV17M", "GeForce4 440 Go 64M" } , + { 0x10DE, 0x017A, "NV17GL.2", "Quadro4 200/400 NVS" } , + { 0x10DE, 0x017B, "NV17GL.3", "Quadro4 550 XGL" } , + { 0x10DE, 0x017C, "NV17M", "Quadro4 500 GoGL" } , + { 0x10DE, 0x0181, "NV18B", "NVIDIA GeForce MX440 with AGP8X" } , + { 0x10DE, 0x0182, "NV18.2", "GeForce4 MX 440 with AGP 8X" } , + { 0x10DE, 0x0183, "NV18.4", "GeForce4 MX 420 with AGP 8X" } , + { 0x10DE, 0x0185, "NV18.6", "GeForce4 MX 4000" } , + { 0x10DE, 0x0186, "NV18M", "GeForce4 448 Go" } , + { 0x10DE, 0x0187, "nv18m", "Geforce4 488 Go" } , + { 0x10DE, 0x018A, "Quadro NVS", "Quadro NVS with AGP8X" } , + { 0x10DE, 0x018D, "NV18M", "GeForce4 448 Go" } , + { 0x10DE, 0x0191, "G80", "Geforce 8800GTX 768MB" } , + { 0x10DE, 0x0193, "G80", "NVIDIA GeForce 8800 GTS" } , + { 0x10DE, 0x019D, "G80", "Nvidia Quadro FX 5600" } , + { 0x10DE, 0x019E, "G80", "Nvidia Quadro FX4600" } , + { 0x10DE, 0x01A0, "NVCrush11", "GeForce2 Integrated Graphics" } , + { 0x10DE, 0x01A4, "nForce", "AGP Controller" } , + { 0x10DE, 0x01A5, "nForce", "AGP Controller" } , + { 0x10DE, 0x01A6, "nForce", "AGP Controller" } , + { 0x10DE, 0x01A8, "nForce 220", "Memory Controller (SDR)" } , + { 0x10DE, 0x01A9, "nForce 420", "Memory Controller (SDR)" } , + { 0x10DE, 0x01AA, "nForce 220/230", "Memory Controller (DDR)" } , + { 0x10DE, 0x01AB, "nForce 415/420/430", "Memory Controller (DDR)" } , + { 0x10DE, 0x01AC, "nForce 2x0/415/4x0", "Memory Controller" } , + { 0x10DE, 0x01AD, "nForce 2x0/415/4x0", "Memory Controller" } , + { 0x10DE, 0x01B0, "nForce MCP", "Audio Processing Unit (Dolby Digital)" } , + { 0x10DE, 0x01B1, "nForce MCP-S", "Audio Codec Interface" } , + { 0x10DE, 0x01B2, "nForce", "HUB Interface" } , + { 0x10DE, 0x01B4, "nForce MCP", "SMBus Controller" } , + { 0x10DE, 0x01B7, "nForce", "AGP Bridge" } , + { 0x10DE, 0x01B8, "nForce", "PCI Bridge" } , + { 0x10DE, 0x01BC, "nForce MCP", "ATA Controller" } , + { 0x10DE, 0x01C1, "nForce MCP", "AC97 Modem" } , + { 0x10DE, 0x01C2, "nForce MCP", "OHCI USB Controller" } , + { 0x10DE, 0x01C3, "nForce MCP", "Networking Adapter" } , + { 0x10DE, 0x01D1, "unknown", "NVIDIA GeForce 7300 LE" } , + { 0x10DE, 0x01D3, "nVidia", "nVidia GeForce 7300 SE" } , + { 0x10DE, 0x01D7, "unknown", "nVIDIA Quadro NVS 110M" } , + { 0x10DE, 0x01D8, "G72M", "GeForce Go 7400" } , + { 0x10DE, 0x01DC, "nvidia mobile graphics", "NVIDIA Quadro FX 350M" } , + { 0x10DE, 0x01DD, "7500LE", "?" } , + { 0x10DE, 0x01DF, "0000", "0000" } , + { 0x10DE, 0x01E0, "nForce2", "AGP Controller" } , + { 0x10DE, 0x01E1, "nForce2", "AGP Controller" } , + { 0x10DE, 0x01E8, "nForce2", "AGP Host to PCI Bridge" } , + { 0x10DE, 0x01EA, "nForce2", "Memory Controller 0" } , + { 0x10DE, 0x01EB, "nForce2", "Memory Controller 1" } , + { 0x10DE, 0x01EC, "nForce2", "Memory Controller 2" } , + { 0x10DE, 0x01ED, "nForce2", "Memory Controller 3" } , + { 0x10DE, 0x01EE, "nForce2", "Memory Controller 4" } , + { 0x10DE, 0x01EF, "nForce2", "Memory Controller 5" } , + { 0x10DE, 0x0200, "NV20", "GeForce3" } , + { 0x10DE, 0x0201, "NV2", "GeForce3 Ti 200" } , + { 0x10DE, 0x0202, "NV20BR", "GeForce3 Ti 500" } , + { 0x10DE, 0x0203, "NV20DCC", "Quadro DCC" } , + { 0x10DE, 0x0221, "unknown", "NVIDIA GeForce 6200" } , + { 0x10DE, 0x0241, "NVS 210S", "nVidia GForce 6150, build in DELL Optiplex 740 (AMD Processor)" } , + { 0x10DE, 0x0242, "unknown", "NVIDIA GeForce 6100" } , + { 0x10DE, 0x0244, "Geforce Go 6150", "Geforce Go 6150" } , + { 0x10DE, 0x0250, "NV25", "GeForce4 Ti 4600" } , + { 0x10DE, 0x0251, "NV25.2", "Gforce4 Ti 4400" } , + { 0x10DE, 0x0253, "NVIDIA Corporation", "Geforce4 TI 4200 128 Mo" } , + { 0x10DE, 0x0258, "NV25GL.1", "Quadro4 900 XGL" } , + { 0x10DE, 0x0259, "NV25GL.2", "Quadro4 750 XGL" } , + { 0x10DE, 0x025B, "NV25GL.4", "Quadro4 700 XGL" } , + { 0x10DE, 0x0264, "NVIDIA SMB Bus Controller", "NVIDIA nForce PCI System Management" } , + { 0x10DE, 0x0265, "MCP51", "PATA Controller" } , + { 0x10DE, 0x0266, "MCP51S", "NVIDIA nForce 430/410 Serial ATA Controller" } , + { 0x10DE, 0x0267, "MCP51S", "NVIDIA nForce 430/410 Serial ATA Controller" } , + { 0x10DE, 0x0268, "430", "NVIDIA nForce Networking Controller" } , + { 0x10DE, 0x0269, "2A34103C", "MCP51 Ethernet Controller " } , + { 0x10DE, 0x026C, "6150", "AMD" } , + { 0x10DE, 0x0271, "unknown", "Coprocessor" } , + { 0x10DE, 0x0280, "NV28.1", "GeForce4 Ti 4800" } , + { 0x10DE, 0x0281, "NV28.2", "GeForce4 Ti 4200 with AGP 8X" } , + { 0x10DE, 0x0282, "NV28.3", "GeForce4 Ti 4800 SE" } , + { 0x10DE, 0x0286, "???", "GeForce4 4200 Go" } , + { 0x10DE, 0x0288, "NV28GL.1", "Quadro4 980 XGL" } , + { 0x10DE, 0x0289, "NV28GL.2", "Quadro4 780 XGL" } , + { 0x10DE, 0x028C, "NV28GL", "Quadro4 700 GoGL" } , + { 0x10DE, 0x0291, "0x0401", "BLISS GeForce 7900 GT bios" } , + { 0x10DE, 0x0297, "G71", "NVIDIA GeForce Go 7950 GTX" } , + { 0x10DE, 0x029C, "G71", "Nvidia Quadro FX 5500" } , + { 0x10DE, 0x029D, "G71", "Quadro FX 3500" } , + { 0x10DE, 0x02A0, "NV2A", "GeForce3 Integrated GPU" } , + { 0x10DE, 0x02e0, "???", "GeForce 7600 GT" } , + { 0x10DE, 0x02E2, "-", "Video Card GPU BFG 7300 512MB GT" } , + { 0x10DE, 0x0300, "NV30.1", "GeForce FX" } , + { 0x10DE, 0x0301, "NV30.2", "GeForce FX 5800 Ultra" } , + { 0x10DE, 0x0302, "NV30.3", "GeForce FX 5800" } , + { 0x10DE, 0x0308, "NV30GL.1", "Quadro FX 2000" } , + { 0x10DE, 0x0309, "NV30GL.2", "Quadro FX 1000" } , + { 0x10DE, 0x030A, "NV30GL", "ICE FX 2000" } , + { 0x10DE, 0x0311, "NV31.1", "GeForce FX 5600 Ultra" } , + { 0x10DE, 0x0312, "NV31.2", "GeForce FX 5600" } , + { 0x10DE, 0x0313, "NV31?", "???" } , + { 0x10DE, 0x0314, "NV31", "GeForce FX 5600XT" } , + { 0x10DE, 0x0318, "NV31GL.1", "???" } , + { 0x10DE, 0x0319, "NV31GL.2", "???" } , + { 0x10DE, 0x031A, "NV31GL", "NVIDIA NV31GL" } , + { 0x10DE, 0x031B, "NV31B", "NVIDIA GeForce FX Go5600" } , + { 0x10DE, 0x031C, "NV31C", "NVIDIA Quadro FX Go700" } , + { 0x10DE, 0x0321, "NV34.2", "GeForce FX 5200 Ultra" } , + { 0x10DE, 0x0322, "NV34.3", "GeForce FX 5200" } , + { 0x10DE, 0x0323, "NV34.4", "GeForce FX 5200LE" } , + { 0x10DE, 0x0324, "NV", "nVidia GeForce FX Go 5200, 128MB" } , + { 0x10DE, 0x0325, "nv36m", "GeForce FX Go 5700" } , + { 0x10DE, 0x0326, "NV34.6", "GeForce FX 5500" } , + { 0x10DE, 0x0327, "NV34.7", "GeForce FX 5100" } , + { 0x10DE, 0x0328, "NV34GL", "Nvidia NV34GL" } , + { 0x10DE, 0x0329, "G73", "Geforce 7600GS" } , + { 0x10DE, 0x032A, "NV34GL.3", "Quadro NVS 280" } , + { 0x10DE, 0x032B, "NV34GL.4", "Quadro FX 500" } , + { 0x10DE, 0x032C, "NV34GL", "NVIDIA NV34GL" } , + { 0x10DE, 0x032D, "NV34M", "GeForce FX Go5100" } , + { 0x10DE, 0x032F, "NV34GL", "???" } , + { 0x10DE, 0x0330, "???", "GeForce FX 5900 Ultra" } , + { 0x10DE, 0x0331, "???", "GeForce FX 5900" } , + { 0x10DE, 0x0332, "???", "GeForce FX 5900XT" } , + { 0x10DE, 0x0333, "NV38", "GeForce FX 5950 Ultra" } , + { 0x10DE, 0x0334, "NV35.4", "GeForce FX 5900ZT" } , + { 0x10DE, 0x0338, "NV35GL", "Quadro FX 3000" } , + { 0x10DE, 0x0341, "NV36.1", "GeForce FX 5700 Ultra" } , + { 0x10DE, 0x0342, "NV36.2", "GeForce FX 5800" } , + { 0x10DE, 0x0343, "NV36.3", "GeForce FX 5700LE" } , + { 0x10DE, 0x0344, "NV36.4", "GeForce FX 5700VE" } , + { 0x10DE, 0x0345, "NV36.5", "???" } , + { 0x10DE, 0x0347, "??", "Nvidia 5700 from hp" } , + { 0x10DE, 0x0348, "NV36M", "GeForce FX Go5600" } , + { 0x10DE, 0x034E, "nv36GL", "Quadro FX 1100" } , + { 0x10DE, 0x034F, "NV36GL?", "???" } , + { 0x10DE, 0x036C, "81FB1043", "Standard OpenHCD USB Hostcontroller" } , + { 0x10DE, 0x036d, "81FB1043", "Standard PCI-to-USB Enhanced Hostcontroller" } , + { 0x10DE, 0x036E, "MCP55", "MCP55 PATA Controller" } , + { 0x10DE, 0x036F, "MCP55", "MCP55 SATA/RAID Controller" } , + { 0x10DE, 0x0371, "ADI 1988", "MCP55 High Definition Audio" } , + { 0x10DE, 0x037E, "MCP55", "MCP55 SATA/RAID Controller" } , + { 0x10DE, 0x037F, "MCP55S", "MCP55 SATA/RAID Controller" } , + { 0x10DE, 0x0391, "G73 B1", "Ge-Force 7600GT" } , + { 0x10DE, 0x0392, "NVIDIA GeForce 7600 GS", "NVIDIA GeForce 7600 GS" } , + { 0x10DE, 0x0393, "UNKOWN", "NVIDIA GeForce 7300GT" } , + { 0x10DE, 0x0398, "G73", "NVIDIA GeForce Go 7600" } , + { 0x10DE, 0x039E, "Quadro FX 560", "Quadro FX 560" } , + { 0x10DE, 0x03D0, "unknown", "NVIDIA GeForce 6100 nForce 430" } , + { 0x10DE, 0x03E0, "nForce 430", "PCI standard ISA bridge" } , + { 0x10DE, 0x03E7, "MCP61", "MCP61 SATA/RAID Controller" } , + { 0x10DE, 0x03EC, "MCP61", "MCP61 PATA Controller" } , + { 0x10DE, 0x03EF, "nForce 405", "Nvidia Networking Card" } , + { 0x10DE, 0x03F0, "MCP61", "High Definition Audio" } , + { 0x10DE, 0x03F6, "MCP61", "MCP61 SATA/RAID Controller" } , + { 0x10DE, 0x03F7, "MCP61", "MCP61 SATA/RAID Controller" } , + { 0x10DE, 0x0402, "0402", "gainward bliss 8600 gt 512mo silent fx pcx" } , + { 0x10DE, 0x0407, "NVIDIA GeForce 8600M GT", "NVIDIA GeForce 8600M GT" } , + { 0x10DE, 0x040C, "NVIDIA Quadro NVS 570M", "Mobile Quadro FX/NVS video card" } , + { 0x10DE, 0x0421, "G86", "GeForce 8500 GT" } , + { 0x10DE, 0x0423, "G86", "NVIDIA Geforce 8300 GS" } , + { 0x10DE, 0x0427, "unknown", "Geforce 8400M GS" } , + { 0x10DE, 0x0428, "NVIDIA� GeForce 8400M G", "NVIDIA� GeForce 8400M G" } , + { 0x10DE, 0x0429, "Unknown", "nVidia Quadro FX 570M" } , + { 0x10DE, 0x042b, "8400 ??", "NVIDIA Quadro NVS 135M" } , + { 0x10DE, 0x042D, "Quadro FX 360 M", "Quadro FX 360 M (Mobile)" } , + { 0x10DE, 0x042f, "NVS 290", "NVIDIA Quadro NVS 290" } , + { 0x10DE, 0x0448, "MCP65", "MCP65 PATA Controller" } , + { 0x10DE, 0x044C, "MCP65", "MCP65 RAID" } , + { 0x10DE, 0x044D, "MCP65", "MCP65 AHCI" } , + { 0x10DE, 0x044E, "MCP67D", "MCP67D AHCI" } , + { 0x10DE, 0x044F, "MCP65", "MCP65 ?AHCI" } , + { 0x10DE, 0x045D, "MCP65", "MCP65 SATA Controller(IDE mode)" } , + { 0x10DE, 0x054, "NVidia nForce 4 SLI", "IDE Controller" } , + { 0x10DE, 0x0550, "MCP67", "MCP67 SATA Controller(IDE mode)" } , + { 0x10DE, 0x0554, "MCP67", "MCP67 AHCI" } , + { 0x10DE, 0x0555, "MCP67", "MCP67 AHCI" } , + { 0x10DE, 0x0556, "MCP67", "MCP67 AHCI" } , + { 0x10DE, 0x0558, "MCP67", "MCP67 RAID" } , + { 0x10DE, 0x0559, "MCP67", "MCP67 RAID" } , + { 0x10DE, 0x055A, "MCP67", "MCP67 RAID" } , + { 0x10DE, 0x0560, "MCP67", "MCP67 PATA Controller" } , + { 0x10DE, 0x056C, "MCP73", "MCP73 PATA" } , + { 0x10DE, 0x0611, "8800 GT", "Alphadog edition from XFX" } , + { 0x10DE, 0x0622, "nVidia GeForce 9600GT", "nVidia" } , + { 0x10DE, 0x0640, "G96-300-A1", "Nvidia 9500GT graphic controller" } , + { 0x10DE, 0x0644, "G96", "GeForce 9500 GS" } , + { 0x10DE, 0x0645, "G96", "GeForce 9500 GS" } , + { 0x10DE, 0x0649, "G96", "nVidia GeForce 9600M GT" } , + { 0x10DE, 0x0760, "MCP78 NIC", "NForce Network Controller" } , + { 0x10DE, 0x0768, "MCP ?", "AHCI Controller" } , + { 0x10DE, 0x07B5, "MCP72", "MCP72 AHCI" } , + { 0x10DE, 0x07B9, "MCP72", "MCP72 RAID" } , + { 0x10DE, 0x07D8, "nForce 7100-630i (MCP73PV)", "nForce 7100-630i (MCP73PV)" } , + { 0x10DE, 0x07DC, "nForce 7100-630i (MCP73PV)", "nForce 7100-630i (MCP73PV)" } , + { 0x10DE, 0x07F0, "MCP73", "MCP73 SATA(IDE mode)" } , + { 0x10DE, 0x07F4, "MCP73", "MCP73 AHCI1" } , + { 0x10DE, 0x07F5, "MCP73", "MCP73 AHCI2" } , + { 0x10DE, 0x07F6, "MCP73", "MCP73 AHCI3" } , + { 0x10DE, 0x07F7, "MCP73", "MCP73 AHCI4" } , + { 0x10DE, 0x07F8, "MCP73", "MCP73 RAID1" } , + { 0x10DE, 0x07F9, "MCP73", "MCP73 RAID2" } , + { 0x10DE, 0x07FA, "MCP73", "MCP73 RAID3" } , + { 0x10DE, 0x07FB, "MCP73", "MCP73 RAID4" } , + { 0x10DE, 0x0aa3, "nForce", "NVIDIA nForce System Management Controller" } , + { 0x10DE, 0x0AB8, "MCP79", "MCP79 AHCI1" } , + { 0x10DE, 0x0AB9, "MCP79", "MCP79 AHCI2" } , + { 0x10DE, 0x0ABC, "MCP79", "MCP79 RAID1" } , + { 0x10DE, 0x0ABD, "MCP79", "MCP79 RAID2" } , + { 0x10DE, 0x0AD0, "MCP78", "SATA Controller IDE mode" } , + { 0x10DE, 0x0BC4, "MCP?", "AHCI Controller" } , + { 0x10DE, 0x0BC5, "MCP?", "AHCI Controller" } , + { 0x10DE, 0x0BCC, "MCP?", "Raid Controller" } , + { 0x10DE, 0x0BCD, "MCP?", "Raid Controller" } , + { 0x10DE, 0x10DE, "NV3", "Riva 128" } , + { 0x10DE, 0x110, "nv11", "geforcemx/mx400" } , + { 0x10DE, 0x161, "NV44", "GeForce 6200 TurboCache" } , + { 0x10DE, 0x181, "NV18B", "GeForce4 MX 440 AGP 8X" } , + { 0x10DE, 0x247, "NVS210S", "GF6150" } , + { 0x10DE, 0x26C, "6150", "AMD" } , + { 0x10DE, 0x69, "nVidia MCP2T", "nVidia MCP2T in MSI MEGA 180" } , + { 0x10DE, 0x8001, "MCP73", "nVidia MCP73 HDMI Audio Driver" } , + { 0x10DE, 0x026C, "6150", "nVidia GeForce" } , + { 0x10DF, 0x10DF, "Light Pulse", "Fibre Channel Adapter" } , + { 0x10DF, 0x1AE5, "LP6000", "Fibre Channel Host Adapter" } , + { 0x10DF, 0xF0A5, "PL1050Ex", "Emulex 1050EX FC HBA - 2GB PCI-EXPRESS" } , + { 0x10DF, 0xF0E5, "?", "LPe1150" } , + { 0x10DF, 0xF100, "LPe12000", "Fibre Channel Adapter" } , + { 0x10DF, 0xF700, "LP7000", "Fibre Channel Host Adapter" } , + { 0x10DF, 0xF800, "LP8000", "Fibre Channel Host Adapter" } , + { 0x10DF, 0xF900, "????", "Light Pulse LP9002 2Gb" } , + { 0x10DF, 0xF980, "LP9802 / DC", "LP9802 & LP9802DC HBA adapter" } , + { 0x10DF, 0xFA00, "LP10000", "Fibre Channel Host Adapter" } , + { 0x10DF, 0xfd00, "L2A2860 HELIOS v1.11", "Emulex LP11002" } , + { 0x10DF, 0xfe00, "LPe11002-M4", "Dual Channel 4Gb/s" } , + { 0x10E1, 0x0391, "TRM-S1040", "0000" } , + { 0x10E1, 0x690C, "DC-690c", "" } , + { 0x10E1, 0xDC20, "DC-290", "EIDE Controller" } , + { 0xC0DE, 0x5600, "62802", "" } , + { 0xC0DE, 0xC0DE, "62802-51", "oZ0030" } , + { 0x10E3, 0x0000, "CA91C042/142", "Universe/II VMEbus Bridge" } , + { 0x10E3, 0x0148, "Tundra Tsi148", "PCI/X-to-VME Bridge" } , + { 0x10E3, 0x0513, "Tsi320", "Dual-Mode PCI-to-PCI Bus Bridge" } , + { 0x10E3, 0x0850, "Tsi850", "Power PC Dual PCI Host Bridge" } , + { 0x10E3, 0x0854, "Tsi850", "Power PC Single PCI Host Bridge" } , + { 0x10E3, 0x0860, "CA91C860", "QSpan Motorola Processor Bridge" } , + { 0x10E3, 0x0862, "CA91L862A", "QSpan II PCI-to-Motorola CPU Bridge" } , + { 0x10E3, 0x8260, "CA91L8200/8260", "PowerSpan II PowerPC-to-PCI Bus Switch" } , + { 0x10E3, 0x8261, "CA91L8200/8260", "PowerSpan II PowerPC-to-PCI Bus Switch" } , + { 0x10E8, 0x2011, "Q-Motion pci 264", "Video Capture/Edit board" } , + { 0x10E8, 0x4750, "S5920Q 00144 a038", "amcc PCI MatchMaker" } , + { 0x10E8, 0x5920, "S5920q", "amcc" } , + { 0x10E8, 0x8033, "BBK-PCI light", "Transputer Link Interface" } , + { 0x10E8, 0x8043, "LANai4.x", "Myrinet LANai interface chip" } , + { 0x10E8, 0x8062, "S5933", "Parastation" } , + { 0x10E8, 0x807D, "S5933", "PCI44" } , + { 0x10E8, 0x8088, "FS", "Kingsberg Spacetec Format Synchronizer" } , + { 0x10E8, 0x8089, "SOB", "Kingsberg Spacetec Serial Output Board" } , + { 0x10E8, 0x809C, "S5933", "Traquair HEPC3" } , + { 0x10E8, 0x80b1, "Data Fire Basic 4MB PCI", "Active ISDN Controller" } , + { 0x10E8, 0x80b9, "PCI MATCHMAKER S5933QC", "Some sort of Bridge?" } , + { 0x10E8, 0x80D7, "PCI-9112", "Data Acquisition Card (ADLINK)" } , + { 0x10E8, 0x80D8, "PCI-7200", "40MB/s 32-channels Digital I/O card (ADLINK)" } , + { 0x10E8, 0x80D9, "PCI-9118", "Data Acquisition Card (ADLINK)" } , + { 0x10E8, 0x80DA, "", "" } , + { 0x10E8, 0x811A, "PCI-DSlink", "PCI-IEEE1355-DS-DE interface" } , + { 0x10E8, 0x8170, "S5933", "Matchmaker PCI Chipset Development Tool" } , + { 0x10EA, 0x1680, "IGA-1680", "svga" } , + { 0x10EA, 0x1682, "IGA-1682", "video" } , + { 0x10EA, 0x1683, "IGA-1683", "" } , + { 0x10EA, 0x2000, "CyberPro 2010", "TV output ram 2MB Cyberpro2010" } , + { 0x10EA, 0x2010, "CyberPro 20xx/2000A", "vbcvbcvbcvb" } , + { 0x10EA, 0x5000, "CyberPro 5000", "" } , + { 0x10EA, 0x5050, "CyberPro 5050", "" } , + { 0x10EB, 0x0101, "3GA", "64 bit graphics processor" } , + { 0x10EB, 0x8111, "Twist3", "Frame Grabber" } , + { 0x9005, 0x0010, "AIC-7890AB scsi controller", "AHA-2940U2W/U2B,2950U2W Ultra2 SCSI" } , + { 0x9005, 0x0011, "11111", "AHA-2930U2 Ultra2 SCSI Host Adapter" } , + { 0x9005, 0x0013, "AIC-7890/1", "SCSI Controller" } , + { 0x9005, 0x001F, "AIC-7890 AB for Windows XP", "Ultra2-Wide SCSI controller" } , + { 0x9005, 0x0020, "AIC-789x", "SCSI Controller" } , + { 0x9005, 0x002F, "AIC-789x", "SCSI Controller" } , + { 0x9005, 0x0030, "AIC-789x", "SCSI Controller" } , + { 0x9005, 0x003F, "AIC-789x", "SCSI Controller" } , + { 0x9005, 0x0050, "", "AHA-3940U2x/3950U2x Ultra2 SCSI Adapter" } , + { 0x9005, 0x0051, "", "AHA-3950U2x Ultra2 SCSI Adapter" } , + { 0x9005, 0x0053, "AIC-7896", "SCSI Controller" } , + { 0x9005, 0x005F, "AIC-7896/7", "Ultra2 SCSI Controller" } , + { 0x9005, 0x0080, "AIC-7892Q", "Ultra160/m PCI SCSI Controller" } , + { 0x9005, 0x0081, "AIC-7892B", "Ultra160 SCSI Controller" } , + { 0x9005, 0x0083, "AIC-7892D", "Ultra160 SCSI Controller" } , + { 0x9005, 0x008F, "AIC-7892", "Ultra160 SCSI Controller" } , + { 0x9005, 0x00C0, "AIC-7899A", "Ultra160 SCSI Controller" } , + { 0x9005, 0x00C1, "AIC-7899B", "Ultra160 SCSI Controller" } , + { 0x9005, 0x00C3, "AIC-7899D", "Ultra160 SCSI Controller" } , + { 0x9005, 0x00C5, "", "RAID Subsystem HBA" } , + { 0x9005, 0x00CF, "AIC-7899G", "Ultra160 SCSI Controller" } , + { 0x9005, 0x0258, "AAC-RAID", "Adaptec AAR-2610SA SATA 6-Port Raid" } , + { 0x9005, 0x0285, "Adaptec 2410SA SATA RAID", "PCIX133 32/64bit" } , + { 0x9005, 0x041F, "AIC 9410", "SAS/SATA Controller" } , + { 0x9005, 0x043E, "AIC9450W", "SAS/SATA Controller" } , + { 0x9005, 0x8000, "ASC-29320A", "Ultra320 SCSI Controller" } , + { 0x9005, 0x800F, "AIC-7901", "Ultra320 SCSI Controller" } , + { 0x9005, 0x8010, "ASC-39320", "Ultra320 SCSI Controller" } , + { 0x9005, 0x8011, "ASC-39320D", "Ultra320 SCSI Controller" } , + { 0x9005, 0x8012, "ASC-29320", "Ultra320 SCSI Controller" } , + { 0x9005, 0x8014, "ASC-29320LP", "Ultra320 SCSI Controller" } , + { 0x9005, 0x8015, "ASC-39320", "Ultra320 SCSI Controller" } , + { 0x9005, 0x8016, "ASC-39320A", "Ultra320 SCSI Controller" } , + { 0x9005, 0x8017, "ASC-29320ALP", "Ultra320 SCSI Controller" } , + { 0x9005, 0x801C, "AIC-?????", "Ultra320 SCSI Controller" } , + { 0x9005, 0x801D, "AIC-7902B", "Ultra320 SCSI Controller" } , + { 0x9005, 0x801E, "AIC-7901", "Ultra320 SCSI Controller" } , + { 0x9005, 0x801F, "AIC-7902", "Ultra320 SCSI Controller" } , + { 0x9005, 0x8080, "ASC-29320A", "Ultra320 HostRAID Controller" } , + { 0x9005, 0x808F, "AIC-7901", "Ultra320 HostRAID Controller" } , + { 0x9005, 0x8090, "ASC-39320", "HostRAID SCSI Controller" } , + { 0x9005, 0x8091, "ASC-39320D", "HostRAID SCSI Controller" } , + { 0x9005, 0x8092, "ASC-29320", "HostRAID SCSI Controller" } , + { 0x9005, 0x8093, "ASC-29320B", "HostRAID SCSI Controller" } , + { 0x9005, 0x8094, "ASC-29320LP", "HostRAID SCSI Controller" } , + { 0x9005, 0x8095, "ASC-39320", "HostRAID SCSI Controller" } , + { 0x9005, 0x8096, "ASC-39320A", "HostRAID SCSI Controller" } , + { 0x9005, 0x8097, "ASC-29320ALP", "HostRAID SCSI Controller" } , + { 0x9005, 0x809C, "ASC-39320D", "HostRAID SCSI Controller" } , + { 0x9005, 0x809D, "AIC-7902B", "HostRAID SCSI Controller" } , + { 0x9005, 0x809E, "AIC-7901A", "HostRAID SCSI Controller" } , + { 0x9005, 0x809F, "AIC-7902B", "HostRAID SCSI Controller" } , + { 0x10EC, 0x0139, "rtl8139B", "ethernet 10/100" } , + { 0x10EC, 0x0139, "rtl8139B", "ethernet 10/100" } , + { 0x10EC, 0x0260, "RTL260", "Driver MS UAA for HD Audio" } , + { 0x10EC, 0x0262, "ALC882", "Realtek High Definition Audio" } , + { 0x10EC, 0x0268, "Realtek ALC268", "Audio Device on High Definition Audio Bus" } , + { 0x10EC, 0x0660, "Realtek HD Audio", "High Definition Audio" } , + { 0x10EC, 0x0662, "ALC662", "Realtek ALC662 HD Audio" } , + { 0x10EC, 0x0880, "al880", "REALTEK ALC880" } , + { 0x10EC, 0x0883, "alc888S", "Realtek High Definition Audio" } , + { 0x10EC, 0x0885, "ALC885", "7.1+2 Channel High-Performance HDA Codec with Content Protection" } , + { 0x10EC, 0x0888, "realtek high definition audio", "Realtek Azak lia chipset" } , + { 0x10EC, 0x8021, "RTL8029AS", "NIC" } , + { 0x10EC, 0x8029, "RTL8029(as)pci ethernet nic", "RTL8029(as)pci ethernet nic" } , + { 0x10EC, 0x8101L, "8101E", "10/100 Ethernet" } , + { 0x10EC, 0x8119, "10", "32BIT Card Bus 10/100 (10EC-8119)" } , + { 0x10EC, 0x8129, "RTL8139d", "10/100 Fast Ethernet Controller" } , + { 0x10EC, 0x8131, "LFE8139ATX", "" } , + { 0x10EC, 0x8136, "RTL8100-8101E-8102E-PCIEXPRESS", "RTL8100E/RTL8101E/RTL8102E-GR" } , + { 0x10EC, 0x8138, "RT8139B/C", "CardBus Fast Ethernet Adapter" } , + { 0x10EC, 0x8139, "RTL-8139/8139C/8139C+", "Realtek RTL8139 Family PCI Fast Ethernet NIC" } , + { 0x10EC, 0x8167, "8169", "PCI Gigabit Ethernet" } , + { 0x10EC, 0x8168, "RTL8168/8111", "Gigabit Ethernet NIC(NDIS 6.0)" } , + { 0x10EC, 0x8169, "RTL8119", "Single Gigabit LOM Ethernet Controller" } , + { 0x10EC, 0x8180, "RTL8180", "Realtek RTL8180 Wireless LAN (Mini-)PCI NIC" } , + { 0x10EC, 0x8185, "RTL-8185", "IEEE 802.11a/b/g Wireless LAN Controller (rev 20)" } , + { 0x10EC, 0x8186, "RTL8111/8168B", "PCI Express Gigabit Ethernet controller" } , + { 0x10EC, 0x8197, "8187B", "Wireless 802.11b/g 54Mbps USB 2.0 Network Adapter" } , + { 0x10EC, 0x8199, "RTL8187SE", "Single-Chip IEEE 802.11b/g WLAN Controller w/PCI Express Interface" } , + { 0x10EC, 0x9876, "RTL 8168/8111", "GIGABIT ETHERNET LOM" } , + { 0x10ED, 0x7310, "V7310", "VGA Video Overlay Adapter" } , + { 0x10EE, 0x0314, "Spartan XC2S50E", "Communications Controller" } , + { 0x10EE, 0X1001, "8343176", "PCI to H.100 audio interface" } , + { 0x10EE, 0x3FC0, "RME Digi96", "" } , + { 0x10EE, 0x3FC1, "RME Digi96/8", "" } , + { 0x10EE, 0x3FC2, "RME Digi 96/8 Pro", "" } , + { 0x10EE, 0x3FC3, "RME Digi96/8 Pad", "RME Digi96/8 Pad" } , + { 0x10EE, 0x3FC4, "Digi9652", "Hammerfall" } , + { 0x10EE, 0x3FC5, "0", "HDSP 9632" } , + { 0x10EE, 0x5343, "Seamont SC100", "Security Adapter" } , + { 0x10EE, 0x8130, "Durango PMC", "Virtex-II Bridge, XC2V1000-4FG456C" } , + { 0x10EE, 0x8381, "Santos", "Frame Grabber" } , + { 0x10EE, 0xA123, "XA3S1600E", "Spartan 3E" } , + { 0x10EE, 0xA124, "Spartan 3E", "XA3S1600E" } , + { 0x10EF, 0x8154, "M815x", "Token Ring Adapter" } , + { 0x10F0, 0xA800, "VCL-P", "Graphics board" } , + { 0x10F0, 0xB300, "VCL-M", "graphics board" } , + { 0x10F1, 0x1566, "", "IDE/SCSI" } , + { 0x10F1, 0x1677, "", "Multimedia" } , + { 0x10F1, 0x2013, "RS-56 sp-pci", "Conexant RS-56 PCI Modem" } , + { 0x10F4, 0x1300, "rev1.1", "PCI to S5U13x06B0B Bridge Adapter" } , + { 0x10F5, 0xA001, "NDR4000", "NR4600 Bridge" } , + { 0x10F6, 0x0111, "PCIVEN", "CMI8738/C3DX Multimedia Audio Controller" } , + { 0x10FA, 0x0000, "BT848KPF", "GUI Accelerator" } , + { 0x10FA, 0x0001, "", "GUI Accelerator" } , + { 0x10FA, 0x0002, "", "GUI Accelerator" } , + { 0x10FA, 0x0003, "", "GUI Accelerator" } , + { 0x10FA, 0x0004, "", "GUI Accelerator" } , + { 0x10FA, 0x0005, "", "GUI Accelerator" } , + { 0x10FA, 0x0006, "", "GUI Accelerator" } , + { 0x10FA, 0x0007, "", "GUI Accelerator" } , + { 0x10FA, 0x0008, "", "GUI Accelerator" } , + { 0x10FA, 0x0009, "", "GUI Accelerator" } , + { 0x10FA, 0x000A, "", "GUI Accelerator" } , + { 0x10FA, 0x000B, "", "GUI Accelerator" } , + { 0x10FA, 0x000C, "Targa 1000", "Video Capture & Editing card" } , + { 0x10FA, 0x000D, "", "GUI Accelerator" } , + { 0x10FA, 0x000E, "", "GUI Accelerator" } , + { 0x10FA, 0x000F, "", "GUI Accelerator" } , + { 0x10FA, 0x0010, "", "GUI Accelerator" } , + { 0x10FA, 0x0011, "", "GUI Accelerator" } , + { 0x10FA, 0x0012, "", "GUI Accelerator" } , + { 0x10FA, 0x0013, "", "GUI Accelerator" } , + { 0x10FA, 0x0014, "", "GUI Accelerator" } , + { 0x10FA, 0x0015, "", "GUI Accelerator" } , + { 0x10FB, 0x186f, "TH6255", "" } , + { 0x10FC, 0x8139, "4020011B", "10" } , + { 0x10FD, 0x7E50, "-", "-" } , + { 0x1100, 0x3044, "VT6306L", "IEEE1394 Firewire 3 Port PCI Card" } , + { 0x1101, 0x0002, "INI-920", "Ultra SCSI Adapter" } , + { 0x1101, 0x1060, "INI-A100U2W", "Orchid Ultra-2 SCSI Controller" } , + { 0x1101, 0x134A, "", "Ultra SCSI Adapter" } , + { 0x1101, 0x1622, "INIC1620", "PCI SATA Controller" } , + { 0x1101, 0x9100, "INI-9010/9010W", "Fast Wide SCSI Controller" } , + { 0x1101, 0x9400, "INIC-940", "Fast Wide SCSI Controller" } , + { 0x1101, 0x9401, "INIC-935", "Fast Wide SCSI Controller" } , + { 0x1101, 0x9500, "1101", "SCSI Initio ultra" } , + { 0x1101, 0x9502, "INIC-950P", "Ultrawide SCSI controller" } , + { 0x1101, 0x9700, "", "Fast Wide SCSI" } , + { 0x1102, 0x0002, "t4780010004541", "Sound Blaster Live! (Also Live! 5.1) - OEM from DELL - CT4780" } , + { 0x1102, 0x0003, "EMU8008", "AWE64D OEM (CT4600)" } , + { 0x1102, 0x0004, "Creative SB Audigy 2 ZS (WDM)", "Audigy Audio Processor" } , + { 0x1102, 0x0005, "SB0460", "SoundBlaster X-FI XtremeMusic" } , + { 0x1102, 0x0006, "emu10k1x", "Soundblaster Live! 5.1" } , + { 0x1102, 0x0007, "C6SB0410515017656A", "Audigy ls" } , + { 0x1102, 0x0008, "ca0108", "sound blaster Audigy 2" } , + { 0x1102, 0x006, "emu10k1x", "Soundblaster Live! 5.1" } , + { 0x1102, 0x1017, "CT6760", "3D Blaster Banshee PCI CT6760" } , + { 0x1102, 0x1020, "NV5", "3D Blaster RIVA TNT2" } , + { 0x1102, 0x1047, "EV1938", "3D Blaster Annihilator 2" } , + { 0x1102, 0x1371, "ES1371-3", " ES1373 AudioPCI" } , + { 0x1102, 0x2898, "es2898", "es56t-p1" } , + { 0x1102, 0x4001, "EMU10K1", "Audigy IEEE1394a Firewire Controller" } , + { 0x1102, 0x7002, "EMU10000", "Game Port" } , + { 0x1102, 0x7003, "EMU10K2", "Creative Labs SB Audigy MIDI/Game port" } , + { 0x1102, 0x7004, "6", "Game port for SB Live! Series" } , + { 0x1102, 0x7005, "???", "Audigy LS Series Game Port" } , + { 0x1102, 0x7802, "EMU1OK1-NGF", "Environmental Audio (SB Live)" } , + { 0x1102, 0x8938, "EV1938", "Sound" } , + { 0x1102, 1371, "", "" } , + { 0x1105, 0x5000, "", "Multimedia" } , + { 0x1105, 0x8300, "EM8400", "MPEG-2 Decoder" } , + { 0x1105, 0x8400, "EM8400", "MPEG-2 Decoder" } , + { 0x1105, 0x8475, "EM8475", "MPEG-4 Decoder" } , + { 0x1106, 0x0130, "VT6305", "VIA Fire 1394.A OHCI Link Layer Ctrlr" } , + { 0x1106, 0x0198, "", "CPU to PCI Bridge" } , + { 0x1106, 0x0238, "K8T890", "CPU to PCI Bridge" } , + { 0x1106, 0x0259, "unknown", "Host Bridge" } , + { 0x1106, 0x0269, "KT880", "CPU to PCI Bridge" } , + { 0x1106, 0x0282, "K8T880Pro", "CPU to PCI Bridge" } , + { 0x1106, 0x0305, "VT8363A/8365", "Host Bridge" } , + { 0x1106, 0x0391, "VT8363/71", "Host Bridge" } , + { 0x1106, 0x0501, "VT8501", "Host Bridge" } , + { 0x1106, 0x0505, "82C505", "VLB to PCI Bridge" } , + { 0x1106, 0x0561, "82C570 MV", "IDE Controller" } , + { 0x1106, 0x0571, "VT82C586A/B/VT82C686/A/B/VT823x/A/C", "Bus Master IDE Controller" } , + { 0x1106, 0x0576, "82C576", "P54 Ctrlr" } , + { 0x1106, 0x0581, "CX700", "SATA RAID" } , + { 0x1106, 0x0585, "VT82C585VP/VPX", "Host Bus-PCI Bridge" } , + { 0x1106, 0x0586, "VT82C586VP", "PCI-to-ISA Bridge" } , + { 0x1106, 0x0591, "VT8237S", "VIA VT8237A SATA RAID Controller" } , + { 0x1106, 0x0595, "VT82C595", "Apollo VP2 PCI North Bridge" } , + { 0x1106, 0x0596, "VT82C596", "PCI ISA Bridge" } , + { 0x1106, 0x0597, "VT82C597", "Host Bridge (Apollo VP3)" } , + { 0x1106, 0x0598, "VT82C598", "Host Bridge" } , + { 0x1106, 0x0601, "VIA8601", "System Controller" } , + { 0x1106, 0x0605, "VT82c686b", "PM133 System Control" } , + { 0x1106, 0x0680, "VT82C680", "Apollo P6" } , + { 0x1106, 0x0686, "VT82C686/686A/686B", "PCI-to-ISA bridge" } , + { 0x1106, 0x0691, "VIA VT KN133", "Mainboard" } , + { 0x1106, 0x0692, "", "North Bridge" } , + { 0x1106, 0x0693, "VT82C693", "Host Bridge" } , + { 0x1106, 0x0926, "VT86C926", "Amazon PCI Ethernet Controller" } , + { 0x1106, 0x1000, "82C570MV", "Host Bridge" } , + { 0x1106, 0x1106, "060000A", "ISA Bridge w/IDE" } , + { 0x1106, 0x1204, "???", "CPU to PCI" } , + { 0x1106, 0x1238, "K8T890", "CPU to PCI Bridge" } , + { 0x1106, 0x1259, "unknown", "Host Bridge" } , + { 0x1106, 0x1269, "KT880", "CPU to PCI Bridge" } , + { 0x1106, 0x1282, "K8T880Pro", "CPU to PCI Bridge" } , + { 0x1106, 0x1571, "VT82C416", "IDE Controller" } , + { 0x1106, 0x1595, "VT82C595/97", "Host Bridge" } , + { 0x1106, 0x1708, "0x1708", "VEN_1106&DEV_1708" } , + { 0x1106, 0x2006, "VT6105M", "VIA Rhine III VT6105M Fast Ethernet controller" } , + { 0x1106, 0x204, "K8M400 chipset", "CPU to PCI" } , + { 0x1106, 0x2204, "???", "CPU to PCI" } , + { 0x1106, 0x2238, "K8T890", "CPU to PCI Bridge" } , + { 0x1106, 0x2259, "unknown", "Host Bridge" } , + { 0x1106, 0x2269, "KT880", "CPU to PCI Bridge" } , + { 0x1106, 0x2282, "K8T880Pro", "CPU to PCI Bridge" } , + { 0x1106, 0x3038, "VT83C572/6202/82C586A/B/82C596/A/B/82C686A/B etc", "USB&UHCI" } , + { 0x1106, 0x3038, "VT6202", "4 x USB1.0 PCI controller" } , + { 0x1106, 0x3040, "VT82C586A/B", "APM(or ACPIAPIC?)" } , + { 0x1106, 0x3041, "82C570MV", "ISA Bridge w/IDE" } , + { 0x1106, 0x3043, "VT86C100A", "Rhine 10/100 Ethernet Adapter" } , + { 0x1106, 0x3044, "VT6307", "VIA Fire II 1394a OHCI Link Layer Ctrlr1" } , + { 0x1106, 0x3050, "VT82C596/596A/596", "Power Management and SMBus Controller" } , + { 0x1106, 0x3051, "", "Power Management Controller" } , + { 0x1106, 0x3053, "VT6105M", "Rhine III Management Adapter" } , + { 0x1106, 0x3057, "VT82C686A/B", "ACPI Power Management Controller" } , + { 0x1106, 0x3058, "VT8237", "AC97 Audio Codec (All VIA Chipsets)" } , + { 0x1106, 0x3059, "VT8237", "AC97 Enhanced Audio Controller - the 8251 controller is different" } , + { 0x1106, 0x3065, "VT6102", "Rhine II PCI Fast Ethernet Controller||Used by GERICOM in laptop Webengine Advanced" } , + { 0x1106, 0x3068, "VT82C686A/B&VT8231", "&CC_0000=ACPIAPIC,&CC_0780=MC97 MODEM" } , + { 0x1106, 0x3068, "VT82C686A/B&VT8231", "APM(or ACPI?)" } , + { 0x1106, 0x3068, "VT82C686A/B&VT8231", "MC97 MODEM" } , + { 0x1106, 0x3074, "VT8233", "PCI to ISA Bridge" } , + { 0x1106, 0x3086, "VT82C686", "Power" } , + { 0x1106, 0x3091, "VT8633", "CPU to PCI Bridge" } , + { 0x1106, 0x3099, "VT8366/66A/67", "CPU to PCI Bridge" } , + { 0x1106, 0x3101, "VT8653", "CPU to PCI Bridge" } , + { 0x1106, 0x3102, "VT8362", "CPU to PCI Bridge" } , + { 0x1106, 0x3103, "VT8615", "CPU to PCI Bridge" } , + { 0x1106, 0x3104, "VT6202", "USB 2.0 Enhanced Host Controller" } , + { 0x1106, 0x3106, "VT6105M/LOM", "Rhine III PCI Fast Ethernet Controller" } , + { 0x1106, 0x3107, "VT8233/A AC97' Enhance Audio Controller", "PCI to ISA Bridge" } , + { 0x1106, 0x3108, "Unknown", "Via Unichrome S3 VGA - part of a VIA Northbridge" } , + { 0x1106, 0x3109, "VT8233/A AC97' Enhance Audio Controller", "PCI to ISA Bridge" } , + { 0x1106, 0x3112, "VT8361", "CPU to PCI Bridge" } , + { 0x1106, 0x3113, "", "PCI to PCI Bridge" } , + { 0x1106, 0x3116, "VT8375", "CPU-to-PCI Bridge" } , + { 0x1106, 0x3118, "CN400", "Via Built-In VGA S3 Graphics UniChrome� Pro IGP Series CN400" } , + { 0x1106, 0x3119, "VT6120/VT6121/VT6122", "'Velocity' Gigabit Ethernet Controllers" } , + { 0x1106, 0x3122, "VT8623", "CastleRock AGP 8X Controller" } , + { 0x1106, 0x3123, "VT8623", "CPU to PCI Bridge" } , + { 0x1106, 0x3128, "vt8753", "CPU-to-PCI Bridge" } , + { 0x1106, 0x3133, "VT3133", "CPU to PCI Bridge" } , + { 0x1106, 0x3147, "VT8233", "PCI to ISA Bridge" } , + { 0x1106, 0x3148, "VT8751", "CPU-to-PCI Bridge" } , + { 0x1106, 0x3149, "VT8237 Family/ VT6420", "SATA RAID Controller" } , + { 0x1106, 0x3156, "VT8372", "CPU to PCI Bridge" } , + { 0x1106, 0x3158, "", "CPU-to-PCI Bridge" } , + { 0x1106, 0x3164, "VT6410", "VIA VT6410 PATA/PATA RAID Controller" } , + { 0x1106, 0x3168, "VT8374", "P4X400 Host Controller/AGP Bridge" } , + { 0x1106, 0x3177, "VT8235", "PCI to ISA Bridge" } , + { 0x1106, 0x3178, "", "CPU to PCI Bridge" } , + { 0x1106, 0x3188, "K8HTB-8237", "CPU to PCI Bridge" } , + { 0x1106, 0x3189, "VT8377", "CPU to PCI Bridge" } , + { 0x1106, 0x3198, "VEN_1106&DEV_B198&SUBSYS_00000000&REV_00", "CPU-to-PCI Bridge" } , + { 0x1106, 0x3202, "", "CPU to PCI Bridge" } , + { 0x1106, 0x3204, "1394 i2c", "CPU to PCI Bridge" } , + { 0x1106, 0x3205, "", "CPU to PCI Bridge" } , + { 0x1106, 0x3208, "PT890", "CPU to PCI Bridge" } , + { 0x1106, 0x3209, "", "CPU to PCI Bridge" } , + { 0x1106, 0x3213, "", "PCI to PCI Bridge" } , + { 0x1106, 0x3227, "VT8237", "PCI-to-ISA Bridge" } , + { 0x1106, 0x3230, "K8N890CE Display Driver", "Integrated Graphics" } , + { 0x1106, 0x3238, "K8T890", "CPU-to-PCI Bridge" } , + { 0x1106, 0x3249, "VT6421", "VIA VT6421 RAID Controller" } , + { 0x1106, 0x3258, "PT880", "CPU-to-PCI Bridge" } , + { 0x1106, 0x3259, "???", "CPU to PCI Bridge" } , + { 0x1106, 0x3269, "KT880", "CPU to PCI Bridge" } , + { 0x1106, 0x3282, "K8T880Pro", "CPU to PCI Bridge" } , + { 0x1106, 0x3288, "040300", "VIA VT8251/8237A High Definition Audio Controller - HDA Codec Realtek ALC660" } , + { 0x1106, 0x3343, "81CE1043", "?" } , + { 0x1106, 0x3344, "P4M800PRO&8237R", "VIA/S3G UniChrome Pro IGP" } , + { 0x1106, 0x3349, "VT8251", "VIA VT8251 AHCI RAID Controller" } , + { 0x1106, 0x3371, "P4M900", "VIA Chrome9 HC IGP" } , + { 0x1106, 0x4149, "VT6420", "PATA" } , + { 0x1106, 0x4204, "???", "CPU to PCI Bridge" } , + { 0x1106, 0x4238, "???", "CPU to PCI Bridge" } , + { 0x1106, 0x4258, "???", "CPU to PCI Bridge" } , + { 0x1106, 0x4259, "???", "CPU to PCI Bridge" } , + { 0x1106, 0x4269, "KT880", "CPU to PCI Bridge" } , + { 0x1106, 0x4282, "K8T880Pro", "CPU to PCI Bridge" } , + { 0x1106, 0x5030, "VT82C596", "ACPI Power Management Controller" } , + { 0x1106, 0x6100, "VIA VT86C100A", "Rhine II PCI Fast SATA and ethernet controller" } , + { 0x1106, 0x7204, "K8M400", "CPU to PCI Bridge" } , + { 0x1106, 0x7205, "KM400", "VIA Technologies, Inc. VT8378 [S3 UniChrome] Graphics Adapter" } , + { 0x1106, 0x7238, "K8T890", "CPU to PCI Bridge" } , + { 0x1106, 0x7258, "PT880", "CPU to PCI Bridge" } , + { 0x1106, 0x7259, "PM880", "CPU to PCI Bridge" } , + { 0x1106, 0x7269, "KT880", "CPU to PCI Bridge" } , + { 0x1106, 0x7282, "K8T880Pro", "CPU to PCI Bridge" } , + { 0x1106, 0x7353, "CX700", "SATA RAID" } , + { 0x1106, 0x7372, "VT8237", "SATA RAID" } , + { 0x1106, 0x8208, "PT890?", "PCI to AGP Bridge" } , + { 0x1106, 0x8231, "VT8231", "PCI to ISA Bridge" } , + { 0x1106, 0x8235, "VT8751", "vga" } , + { 0x1106, 0x8237, "VT8237", "AC97 Enhanced Audio Controller - the 8251 controller is different" } , + { 0x1106, 0x8305, "VT8363A/65", "PCI to AGP Bridge" } , + { 0x1106, 0x8391, "VT8363/71", "PCI to AGP Bridge" } , + { 0x1106, 0x8501, "VT8501", "PCI to AGP Bridge" } , + { 0x1106, 0x8596, "VT82C596", "PCI to AGP Bridge" } , + { 0x1106, 0x8597, "VT82C597", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0x8598, "VT82C598", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0x8601, "VT82C601", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0x8602, "", "CPU to AGP Bridge" } , + { 0x1106, 0x8605, "VT8605", "PCI-to-PCI Bridge(AGP)" } , + { 0x1106, 0x8691, "VT82C691/693A/694X", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0x8693, "VT82C693", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0x9238, "K8T890", "I/O APIC" } , + { 0x1106, 0x9398, "VT8601", "2D/3D Graphics Accelerator" } , + { 0x1106, 0x9876, "VT8233/A AC97' Enhance Audio Controller", "PCI to ISA Bridge" } , + { 0x1106, 0xA208, "PT890", "PCI-to-PCI Bridge" } , + { 0x1106, 0xA238, "K8T890", "PCI-to-PCI Bridge" } , + { 0x1106, 0xB091, "VT8633", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0xB099, "VT8366/A", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0xB101, "VT8653", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0xB102, "VT8362", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0xB103, "VT8615", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0xB112, "VT8361", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0xB113, "", "I/O APIC" } , + { 0x1106, 0xB115, "VT8363/65", "CPU to AGP Controller" } , + { 0x1106, 0xB116, "VT8375", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0xB133, "vt686b", "CPU to AGP Controller" } , + { 0x1106, 0xB148, "VT8751 Apollo", "PCI-to-Host" } , + { 0x1106, 0xB156, "VT8372", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0xB158, "", "PCI-to-PCI Bridge (AGP)" } , + { 0x1106, 0xB168, "VT8235", "PCI-to-PCI Bridge (AGP 2.0/3.0)" } , + { 0x1106, 0xB188, "3200+", "PCI-to-PCI Bridge (AGP 2.0/3.0)" } , + { 0x1106, 0xB198, "546546", "PCI-to-PCI Bridge (AGP 2.0/3.0)" } , + { 0x1106, 0xB213, "", "I/O APIC" } , + { 0x1106, 0xC208, "PT890", "PCI-to-PCI Bridge" } , + { 0x1106, 0xC238, "K8T890", "PCI-to-PCI Bridge" } , + { 0x1106, 0xD208, "PT890", "PCI-to-PCI Bridge" } , + { 0x1106, 0xD213, "", "PCI to PCI Bridge" } , + { 0x1106, 0xD238, "K8T890", "PCI-to-PCI Bridge" } , + { 0x1106, 0xE208, "PT890", "PCI-to-PCI Bridge" } , + { 0x1106, 0xE238, "K8T890", "PCI-to-PCI Bridge" } , + { 0x1106, 0xF208, "PT890", "PCI-to-PCI Bridge" } , + { 0x1106, 0xF238, "K8T890", "PCI-to-PCI Bridge" } , + { 0x1107, 0x8576, "", "PCI Host Bridge" } , + { 0x1108, 0x0100, "p1690plus-AA", "Token Ring Adapter" } , + { 0x1108, 0x0101, "p1690plus-AB", "2-Port Token Ring Adapter" } , + { 0x1108, 0x0105, "P1690Plus", "Token Ring Adapter" } , + { 0x1108, 0x0108, "P1690Plus", "Token Ring Adapter" } , + { 0x1108, 0x0138, "P1690Plus", "Token Ring Adapter" } , + { 0x1108, 0x0139, "P1690Plus", "Token Ring Adapter" } , + { 0x1108, 0x013C, "P1690Plus", "Token Ring Adapter" } , + { 0x1108, 0x013D, "P1690Plus", "Token Ring Adapter" } , + { 0x1109, 0x1400, "EM110TX", "EX110TX PCI Fast Ethernet Adapter" } , + { 0x110B, 0x0001, "Mpact", "Media Processor" } , + { 0x110B, 0x0002, "GM90C7110VX", "MPACT DVD decoder." } , + { 0x110B, 0x0004, "", "" } , + { 0x13EA, 0x3131, "DS3131", "BoSS Bit Synchronous HDLC Controller" } , + { 0x13EA, 0x3134, "DS3134", "Chateau Channelized T1/E1/HDLC Controller" } , + { 0x13F0, 0x0200, "FFK 8508", "Encore ENL832-TX-ICNT Fast Ethernet PCI Adapter" } , + { 0x13F0, 0x0201, "ST201", "Fast Ehternet Adapter" } , + { 0x13F0, 0x0300, "NX1001", "Network Adapter" } , + { 0x13F0, 0x1023, "NX1101", "Gigabit Ethernet Controller" } , + { 0x13F0, 0x13F0, "-PCIVEN_13F0&DEV_1023&SUBSYS_81801043&REV_414&BC", "ST201 Fast Ethernet Adapter" } , + { 0x13FD, 0x160E, "--", "--" } , + { 0x1400, 0x0001, "", "" } , + { 0x1400, 0x0003, "", "" } , + { 0x1400, 0x0004, "m583mlr", "m583mlr" } , + { 0x1400, 0x1401, "9432 TX", "hd 2600xt" } , + { 0x1409, 0x7168, "40371409", "PCI / ISA Asynchronous UART Signal Chips Solution" } , + { 0x1409, 0x7268, "PCI / ISA IEEE1284 ECP/EPP/SPP/BPP Signal Chips So", "PCI parallel port" } , + { 0x140B, 0x0610, "", "" } , + { 0x140B, 0x615, "NA", "Na" } , + { 0x140B, 0x682, "NA", "NA" } , + { 0x1415, 0x8401, "OX9162", "PCI Interface to local bus" } , + { 0x1415, 0x8403, "OX9162", "Parallel Port" } , + { 0x1415, 0x9500, "OX16PCI954", "Quad UART (disabled)" } , + { 0x1415, 0x9501, "OX16PCI954", "Quad UART" } , + { 0x1415, 0x9505, "OXm16PCI952", "Dual UART" } , + { 0x1415, 0x950A, "OX16PCI954", "Dual PCI UARTS" } , + { 0x1415, 0x950B, "OXCB950", "Integrated High Performance UART" } , + { 0x1415, 0x9510, "OX16PCI954", "PCI Interface (disabled)" } , + { 0x1415, 0x9511, "OX9160", "PCI Interface to 8-bit local bus" } , + { 0x1415, 0x9512, "OX16PCI954", "PCI Interface to 32-bit bus" } , + { 0x1415, 0x9513, "OX16PCI954", "Parallel Port" } , + { 0x1415, 0x9521, "OX16PCI952", "Dual UART" } , + { 0x1415, 0x9523, "OX16PCI952", "Integrated Parallel Port" } , + { 0x141F, 0x6181, "KFIR", "MPEG decoder" } , + { 0x1462, 0x00C1, "NV41.1", "NX6800-TD256E" } , + { 0x1462, 0x4720, "883", "Audio controller" } , + { 0x1462, 0x5071, "883", "Audio controller" } , + { 0x1462, 0x7120, "", "" } , + { 0x1462, 0x7960, "MCP2T", "MCP2T" } , + { 0x1471, 0x0188, "RoadRunner 10", "ADSL PCI" } , + { 0x14A9, 0xad1f, "1", "1" } , + { 0x14B1, 0x1033, "R6795-12", "RH56D-PCI" } , + { 0x14C1, 0x8043, "LANai 9.2 0129", "MyriNet" } , + { 0x14CF, 0x2920, "FPMC-FIO1-F100-1", "Serial I/O Controller aka FPMC-DFLEX64" } , + { 0x14D9, 0x0010, "AP1011/SP1011", "Sturgeon HyperTransport-PCI Bridge" } , + { 0x14E4, 0x034F, "NV36GL?", "???" } , + { 0x14E4, 0x0800, "BCM33xx/47xx", "Sentry5 Chipcommon I/O Controller" } , + { 0x14E4, 0x0804, "BCM33xx/47xx", "Sentry5 PCI Bridge" } , + { 0x14E4, 0x0805, "BCM33xx/47xx", "Sentry5 MIPS32 CPU" } , + { 0x14E4, 0x0806, "BCM33xx/47xx", "Sentry5 Ethernet Controller" } , + { 0x14E4, 0x080B, "BCM33xx/47xx", "Sentry5 Crypto Accelerator" } , + { 0x14E4, 0x080F, "BCM33xx/47xx", "Sentry5 DDR/SDR RAM Controller" } , + { 0x14E4, 0x0811, "BCM33xx/47xx", "Sentry5 External Interface" } , + { 0x14E4, 0x0816, "BCM3302", "Sentry5 MIPS32 CPU" } , + { 0x14E4, 0x14E4, "BCM5787M", "802.11b/g Wireless Lan Controller" } , + { 0x14E4, 0x1600, "BCM5752", "NetXtreme BCM5752 Gigabit Ethernet PCI Express" } , + { 0x14E4, 0x1639, "BCM5709", "NetXtreme II Gigabit Ethernet" } , + { 0x14E4, 0x1644, " BCM5751F", "ven_1102dev_0004" } , + { 0x14E4, 0x1645, "BCM5701", "broadtcomBCM5701 Gigabit Ethernet" } , + { 0x14E4, 0x1646, "BCM5702x1", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x1647, "BCM5703", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x1648, "BCM5704", "NetXtreme Dual Gigabit Adapter" } , + { 0x14E4, 0x164C, "BCM5708", "Broadcom NetXtreme II Gigabit Ethernet Adapter" } , + { 0x14E4, 0x164D, "BCM5702FE", "NetXtreme Fast Ethernet Controller" } , + { 0x14E4, 0x1653, "BCM5788", "Broadcom NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x1654, "BCM5705-", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x1658, "BCM5750", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x1659, "BCM5721", "NetXtreme Gigabit Ethernet PCI Express" } , + { 0x14E4, 0x165A, "94309", "Broadcom NetXtreme BCM5722 Gigabit" } , + { 0x14E4, 0x165D, "BCM5705M", "Broadcom NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x165E, "BCM5705M", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x166a, "BCM5780", "Broadcom NetXtreme Gigabit Ethernet 5780" } , + { 0x14E4, 0x166B, "BCM5780S", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x166D, "BCM5705MFE", "NetXtreme Ethernet 100kB" } , + { 0x14E4, 0x166E, "BCM5705", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x167, "BCM5751F", "NetXtreme Fast Ethernet Controller" } , + { 0x14E4, 0x1672, "BCM5754M", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x1673, "B5755M", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x1676, "BCM5750", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x1677, "BCM5750A1", "NetXtreme Gigabit Ethernet PCI Express" } , + { 0x14E4, 0x1677, "BCM5782", "Broadcom NetExtreme Gigabit Ethernet" } , + { 0x14E4, 0x167A, "BCM5754", "Broadcom NetXtreme Gigabit Ethernet Controller" } , + { 0x14E4, 0x167B, "BCM5755/5780", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x167C, "BCM5750", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x167d, "BCM5751M", "Broadcom NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x167E, "BCM5751FKFB", "vierkant" } , + { 0x14E4, 0x1693, "BCM5787A", "Ethernet Controller Broadcom Netlink Gigabit" } , + { 0x14E4, 0x1696, "BCM5782", "Broadcom NetXtreme Gigabit Ethernet for hp" } , + { 0x14E4, 0x1698, "BCM5784M", "NetLink" } , + { 0x14E4, 0x169A, "BCM5786", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x169B, "BCM5787", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x169C, "BCM5788", "Broadcom NetLink (TM) Gigabit Ethernet" } , + { 0x14E4, 0x169D, "BCM5782k FB", "Broadcom Ethernet Adapter" } , + { 0x14E4, 0x169E, "BCM5754", "NetXtreme Gigabit Ethernet PCI Express" } , + { 0x14E4, 0x16A6, "BCM5702X", "Gigabit Ethernet" } , + { 0x14E4, 0x16A7, "BCM5703X", "Gigabit Ethernet" } , + { 0x14E4, 0x16A8, "BCM5704", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x16AA, "B06BDRV", "BroadCom NetExtreme II Server" } , + { 0x14E4, 0x16C6, "BCM5702A3", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x16C7, "BCM 5703CKHB", "Gigabit Ethernet" } , + { 0x14E4, 0x16DD, "BCM5781", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x16f7, "BCM5753", "NetXtreme BCM5753 Gigabit PCI Express" } , + { 0x14E4, 0x16FD, "BCM5753M", "NetXtreme Gigabit Ethernet PciXpress" } , + { 0x14E4, 0x16FE, "BCM5753F", "NetXtreme Gigabit Ethernet" } , + { 0x14E4, 0x170C, "BCM4401", "Broadcom NetLink 4401 10/100 Ethernet NIC" } , + { 0x14E4, 0x170D, "BCM5901", "NetXtreme" } , + { 0x14E4, 0x170E, "BCM5901", "NetXtreme 100Base-TX" } , + { 0x14E4, 0x1713, "BCM5906m", "Broadcom NetLink (TM) Fast Ethernet" } , + { 0x14E4, 0x3352, "BCM3352", "BCM3352 QAMLink� Single-Chip 4-Line VoIP" } , + { 0x14E4, 0x3360, "BCM3360", "Advanced PHY Broadband Gateway Cable Modem" } , + { 0x14E4, 0x4211, "BCM HPNA", "10Mb/s NIC" } , + { 0x14E4, 0x4212, "BCM V.90", "56k Modem" } , + { 0x14E4, 0x4301, "BCM4301 802.11b", "Dell Truemobile 1180 802.11b MiniPCI" } , + { 0x14E4, 0x4303, "BCM4303", "BCM4301 802.11b802.11b Wireless LAN Controller" } , + { 0x14E4, 0x4305, "BCM4307", "V.90 56k Modem" } , + { 0x14E4, 0x4306, "BCM4306", "Unknown device 4306 (rev 02)" } , + { 0x14E4, 0x4307, "BCM4307", "802.11b Wireless LAN Controller" } , + { 0x14E4, 0x4310, "BCM4310", "BCM4301 802.11bChipcommon I/O Controller" } , + { 0x14E4, 0x4311, "BCM4311", "Broadcom Corporation Dell Wireless 1390 WLAN Mini-PCI Card" } , + { 0x14E4, 0x4312, "BCM4310", "broadcom wireless 1490 (dell)" } , + { 0x14E4, 0x4313, "BCM4310", "usb controller, wireless network card" } , + { 0x14E4, 0x4315, "BCM2046", "Broadcom Wireless " } , + { 0x14E4, 0x4318, "BCM43XX", "Broadcom 802.11b/g" } , + { 0x14E4, 0x4320, "BCM94309", "802.11b/g Wireless LAN Controller" } , + { 0x14E4, 0x4321, "BCM4306", "802.11a Wireless LAN Controller" } , + { 0x14E4, 0x4322, "BCM4306", "UART" } , + { 0x14E4, 0x4323, "BCM4306", "V.90 56k Modem" } , + { 0x14E4, 0x4324, "BCM4309", "802.11a/b/g Wireless LAN Controller" } , + { 0x14E4, 0x4325, "BCM4306", "802.11b/g Wireless LAN Controller" } , + { 0x14E4, 0x4326, "BCM4306", "Chipcommon I/O Controller?" } , + { 0x14E4, 0x4328, "BCM94321KFBG", "Broadcom 4321AGN 802.11a/b/g/draft-n Wi-Fi Solution" } , + { 0x14E4, 0x4329, "?", "?" } , + { 0x14E4, 0x4401, "BCM4401", "10/100 Integrated Ethernet Controller" } , + { 0x14E4, 0x4402, "BCM4402", "10/100 Integrated Ethernet Controller" } , + { 0x14E4, 0x4403, "BCM4402", "V.90 56k Modem" } , + { 0x14E4, 0x4410, "BCM4413", "iLine32 HomePNA 2.0" } , + { 0x14E4, 0x4411, "BCM4212", "V.90 56k Modem" } , + { 0x14E4, 0x4412, "BCM4412", "10/100BaseT Ethernet" } , + { 0x14E4, 0x4430, "BCM44xx", "CardBus iLine32 HomePNA 2.0" } , + { 0x14E4, 0x4432, "BCM44xx", "CardBus 10/100BaseT Ethernet" } , + { 0x14E4, 0x4610, "BCM4610", "Sentry5 PCI to SB Bridge" } , + { 0x14E4, 0x4611, "BCM4610", "Sentry5 iLine32 HomePNA 1.0" } , + { 0x14E4, 0x4612, "BCM4610", "Sentry5 V.90 56k Modem" } , + { 0x14E4, 0x4613, "BCM4610", "Sentry5 Ethernet Controller" } , + { 0x14E4, 0x4614, "BCM4610", "Sentry5 External Interface" } , + { 0x14E4, 0x4615, "BCM4610", "Sentry5 USB Controller" } , + { 0x14E4, 0x4704, "BCM4704", "Sentry5 PCI to SB Bridge" } , + { 0x14E4, 0x4708, "BCM4704", "Crypto Accelerator" } , + { 0x14E4, 0x4710, "BCM4710", "Sentry5 PCI to SB Bridge" } , + { 0x14E4, 0x4711, "BCM47xx", "Sentry5 iLine32 HomePNA 2.0" } , + { 0x14E4, 0x4712, "BCM47xx", "Sentry5 V.92 56k modem" } , + { 0x14E4, 0x4713, "BCM47xx", "Sentry5 Ethernet Controller" } , + { 0x14E4, 0x4714, "BCM47xx", "Sentry5 External Interface" } , + { 0x14E4, 0x4715, "BCM47xx", "Sentry5 USB Controller" } , + { 0x14E4, 0x4716, "BCM47xx", "Sentry5 USB Host Controller" } , + { 0x14E4, 0x4717, "BCM47xx", "Sentry5 USB Device Controller" } , + { 0x14E4, 0x4718, "BCM47xx", "Sentry5 Crypto Accelerator" } , + { 0x14E4, 0x4720, "BCM4712", "MIPS CPU" } , + { 0x14E4, 0x5365, "BCM5365P", "Sentry5 PCI to SB Bridge" } , + { 0x14E4, 0x5600, "BCM5600", "StrataSwitch 24+2 Ethernet Switch Controller" } , + { 0x14E4, 0x5605, "BCM5605", "StrataSwitch 24+2 Ethernet Switch Controller" } , + { 0x14E4, 0x5615, "BCM5615", "StrataSwitch 24+2 Ethernet Switch Controller" } , + { 0x14E4, 0x5625, "BCM5625", "StrataSwitch 24+2 Ethernet Switch Controller" } , + { 0x14E4, 0x5645, "BCM5645", "StrataSwitch 24+2 Ethernet Switch Controller" } , + { 0x14E4, 0x5670, "BCM5670", "8-Port 10GE Ethernet Switch Fabric" } , + { 0x14E4, 0x5680, "BCM5680", "G-Switch 8-Port Gigabit Ethernet Switch Controller" } , + { 0x14E4, 0x5690, "BCM5690", "12-port Multi-Layer Gigabit Ethernet Switch" } , + { 0x14E4, 0x5691, "BCM5691", "GE/10GE 8+2 Gigabit Ethernet Switch Controller" } , + { 0x14E4, 0x5802, "BCM5802", "The BCM5802 Security Processor integrates Broadcom�s IPSec engine (DES, 3DES, HMAC-SHA-1, HMAC-MD5)," } , + { 0x14E4, 0x5805, "BCM5805", "The BCM5805 Security Processor integrates a high-performance IPSec engine (DES, 3DES, HMAC-SHA-1, HM" } , + { 0x14E4, 0x5820, "BCM5820", "Crypto Accelerator" } , + { 0x14E4, 0x5821, "BCM5821", "Crypto Accelerator" } , + { 0x14E4, 0x5822, "BCM5822", "Crypto Accelerator" } , + { 0x14E4, 0x5823, "BCM5823", "Crypto Accelerator" } , + { 0x14E4, 0x5824, "BCM5824", "Crypto Accelerator" } , + { 0x14E4, 0x5840, "BCM5840", "Crypto Accelerator" } , + { 0x14E4, 0x5841, "BCM5841", "Crypto Accelerator" } , + { 0x14E4, 0x5850, "BCM5850", "Crypto Accelerator" } , + { 0x14E4, 0x7321, "BCM5751", "network card integrated" } , + { 0x14E4, 0x7411, "BCM7411", "High Definition Video/Audio Decoder" } , + { 0x14E4, 0x4311, "1364103c", "subsys" } , + { 0x14EB, 0x0020, "BEMx.x", "PCI to S5U13xxxB00B Bridge Adapter" } , + { 0x14EB, 0x0C01, "S1D13808", "Embedded Memory Display Controller" } , + { 0x14F5, 0x2F00, "x", "x" } , + { 0xAA42, 0x03A3, "9400-0931", "CharKey" } , + { 0x14FD, 0x0001, "H260u", "H260u printer server for HP Printer" } , + { 0x165A, 0xC100, "PIXCI CL1", "PCI camera link video capture board" } , + { 0x165A, 0xD200, "PIXCI D2X", "PCI digital video capture board" } , + { 0x165A, 0xD300, "PIXCI D3X", "PCI digital video capture board" } , + { 0x1516, 0x0800, "MTD800", "10/100 Mbps Fast Ethernet Controller" } , + { 0x1516, 0x0803, "Myson MTD803/TAMARACK TC6020", "PCI Ethernet controller" } , + { 0x1516, 0x0891, "MTD891", "10/100/1000 Mbps Gigabit Ethernet Controller" } , + { 0x1112, 0x2200, "2200", "FDDI adapter" } , + { 0x1112, 0x2300, "2300", "Fast Ethernet adapter" } , + { 0x1112, 0X2340, "2340", "4 Port 10/100 UTP Fast Ethernet Adapter" } , + { 0x1112, 0x2400, "2400", "ATM adapter" } , + { 0x1113, 0x1211, "mpx en5038a1", "0A422T1 118F" } , + { 0x1113, 0x1216, "EN5251BE", "accton EN5251BE" } , + { 0x1113, 0x1217, "EN-2242", "Ethernet Adapter" } , + { 0x1113, 0x5105, "EN-1660", "" } , + { 0x1113, 0x9211, "EN-1207D", "Fast Ethernet Adapter" } , + { 0x1113, 0x9511, "SMC en5251be", "0445tabgf16143.1" } , + { 0x1113, 0x9876, "EN5251BE", "Ethernet Controller/ drivers" } , + { 0xA200, 0xa200, "saa1735hl", "tv" } , + { 0x1114, 0x0506, "AT76C506", "802.11b Wireless Network Adaptor" } , + { 0x1114, 0x3202, "AT97SC3202", "TPM - Trusted Platform Module" } , + { 0x1116, 0x0022, "DT3001", "" } , + { 0x1116, 0x0023, "DT3002", "" } , + { 0x1116, 0x0024, "DT3003", "" } , + { 0x1116, 0x0025, "DT3004", "" } , + { 0x1116, 0x0026, "Dt3005", "" } , + { 0x1116, 0x0027, "DT3001-PGL", "" } , + { 0x1116, 0x0028, "DT3003-PGL", "" } , + { 0x1117, 0x9500, "", "max-lc SVGA card" } , + { 0x1117, 0x9501, "", "MaxPCI image processing board" } , + { 0x1119, 0x0000, "GDT6000/6020/6050", "PCI SCSI RAID Controller" } , + { 0x1119, 0x0001, "GDT6000/6010", "PCI 1-channel SCSI RAID Controller" } , + { 0x1119, 0x0002, "GDT6110/6510", "PCI 1-channel SCSI RAID Controller" } , + { 0x1119, 0x0003, "GDT6120/6520", "PCI 2-channel SCSI RAID Controller" } , + { 0x1119, 0x0004, "GDT6530", "PCI 3-channel SCSI RAID Controller" } , + { 0x1119, 0x0005, "GDT6550", "PCI 5-channel SCSI RAID Controller" } , + { 0x1119, 0x0006, "GDT6117/6517", "Wide Ultra SCSI Controller" } , + { 0x1119, 0x0007, "GDT6127/6527", "Wide Ultra SCSI Controller" } , + { 0x1119, 0x0008, "GDT6537", "Wide Ultra SCSI Controller" } , + { 0x1119, 0x0009, "GDT6557/6557-ECC", "Wide Ultra SCSI Controller" } , + { 0x1119, 0x000A, "GDT6115/6515", "Ultra SCSI Controller" } , + { 0x1119, 0x000B, "GDT6125/6525", "Wide SCSI Controller" } , + { 0x1119, 0x000C, "GDT6535", "Wide SCSI Controller" } , + { 0x1119, 0x000D, "GDT6555/6555-ECC", "Wide SCSI Controller" } , + { 0x1119, 0x0100, "GDT6117RP/6517RP", "2 Channel Wide Ultra SCSI" } , + { 0x1119, 0x0101, "GDT6127RP/6527RP", "Wide Ultra SCSI HBA" } , + { 0x1119, 0x0102, "GDT6537RP", "Wide Ultra SCSI HBA" } , + { 0x1119, 0x0103, "GDT6557RP", "Wide Ultra SCSI HBA" } , + { 0x1119, 0x0104, "GDT6111RP/6511RP", "Ultra SCSI HBA" } , + { 0x1119, 0x0105, "GDT6121RP/6521RP", "Ultra SCSI HBA" } , + { 0x1119, 0x0110, "GDT6117RD/6517RD", "Wide Ultra SCSI HBA" } , + { 0x1119, 0x0111, "GDT6127RD/6527RD", "Wide Ultra SCSI HBA" } , + { 0x1119, 0x0112, "GDT6537RD", "Wide Ultra SCSI HBA" } , + { 0x1119, 0x0113, "GDT6557RD", "Wide Ultra SCSI HBA" } , + { 0x1119, 0x0114, "GDT6111RD/6511RD", "Ultra SCSI HBA" } , + { 0x1119, 0x0115, "GDT6127RD/6527RD", "Ultra SCSI HBA" } , + { 0x1119, 0x0118, "GDT6x18RD", "Wide Ultra2 SCSI HBA" } , + { 0x1119, 0x0119, "GDT6x28RD", "Wide Ultra2 SCSI HBA" } , + { 0x1119, 0x011A, "GDT6538RD/6638RD", "Wide Ultra2 SCSI HBA" } , + { 0x1119, 0x011B, "GDT6558RD/6658RD", "Wide Ultra2 SCSI HBA" } , + { 0x1119, 0x0120, "GDT6117RP2/6517RP2", "" } , + { 0x1119, 0x0121, "GDT6127RP2/6527RP2", "" } , + { 0x1119, 0x0122, "GDT6537RP2", "" } , + { 0x1119, 0x0123, "GDT6557RP2", "" } , + { 0x1119, 0x0124, "GDT6111RP2/6511RP2", "" } , + { 0x1119, 0x0125, "GDT6127RP2/6527RP2", "" } , + { 0x1119, 0x0136, "GDT 6x13RS", "" } , + { 0x1119, 0x0137, "GDT 6x23RS", "Disk Array Controller" } , + { 0x1119, 0x0138, "GDT 6x18RS", "" } , + { 0x1119, 0x0139, "GDT 6x28RS", "" } , + { 0x1119, 0x013A, "GDT 6x38RS", "" } , + { 0x1119, 0x013B, "GDT 6x58RS", "" } , + { 0x1119, 0x013C, "GDT 6x33RS", "" } , + { 0x1119, 0x013D, "GDT 6x43RS", "" } , + { 0x1119, 0x013E, "GDT 6x53RS", "" } , + { 0x1119, 0x013F, "GDT 6x63RS", "" } , + { 0x1119, 0x0166, "GDT 7x13RN", "" } , + { 0x1119, 0x0167, "GDT 7x23RN", "" } , + { 0x1119, 0x0168, "GDT7x18RN", "64-bit PCI Wide Untra2 SCSI HBA" } , + { 0x1119, 0x0169, "GDT7x28RN", "64-bit PCI Wide Ultra2 SCSI HBA" } , + { 0x1119, 0x016A, "GDT7538RN/7638RN", "64-bit PCI Wide Ultra2 SCSI HBA" } , + { 0x1119, 0x016B, "GDT7558RN/7658RN", "64-bit PCI Wide Ultra2 SCSI HBA" } , + { 0x1119, 0x016C, "GDT 7x33RN", "" } , + { 0x1119, 0x016D, "GDT 7x43RN", "" } , + { 0x1119, 0x016E, "GDT 7x53RN", "" } , + { 0x1119, 0x016F, "GDT 7x63RN", "" } , + { 0x1119, 0x01D6, "GDT 4x13RZ", "" } , + { 0x1119, 0x01D7, "GDT 4x23RZ", "" } , + { 0x1119, 0x01F6, "GDT 8x13RZ", "" } , + { 0x1119, 0x01F7, "GDT 8x23RZ", "" } , + { 0x1119, 0x01FC, "GDT 8x33RZ", "" } , + { 0x1119, 0x01FD, "GDT 8x43RZ", "" } , + { 0x1119, 0x01FE, "GDT 8x53RZ", "" } , + { 0x1119, 0x01FF, "GDT 8x63RZ", "" } , + { 0x1119, 0x0210, "GDT6519RD/6619RD", "Fibre Channel HBA" } , + { 0x1119, 0x0211, "GDT6529RD/6629RD", "Fibre Channel HBA" } , + { 0x1119, 0x0260, "GDT7519RN/7619RN", "64-bit PCI Fibre Channel HBA" } , + { 0x1119, 0x0261, "GDT7529RN/7629RN", "64-bit PCI Fibre Channel HBA" } , + { 0x1119, 0x0300, "GDT Rx", "" } , + { 0x111A, 0x0000, "155P-MF1", "" } , + { 0x111A, 0x0002, "166P-MF1", "" } , + { 0x111A, 0x0003, "ENI-25P", "ATM Adapter" } , + { 0x111C, 0x0001, "", "Powerbus Bridge" } , + { 0x111D, 0x0001, "IDT77201/211", "NICStAR ATM Adapter" } , + { 0x111D, 0x0003, "IDT77222/252", "MICRO ABR SAR PCI ATM Controller" } , + { 0x111D, 0x0004, "IDT77V252", "MICRO ABR SAR PCI ATM Controller" } , + { 0x111D, 0x76B2, "92HD71B7", "IDT Audio" } , + { 0x111F, 0x4A47, "Precision MX", "Video engine interface" } , + { 0x111F, 0x5243, "", "Frame Capture Bus Interface" } , + { 0x1127, 0x0200, "FireRunner PCA-200", "ATM" } , + { 0x1127, 0x0210, "PCA-200PC", "ATM" } , + { 0x1127, 0x0250, "", "ATM" } , + { 0x1127, 0x0300, "PCA-200E", "ATM adapter" } , + { 0x1127, 0x0310, "", "ATM" } , + { 0x1127, 0x0400, "ForeRunner HE", "ATM Adapter" } , + { 0x8866, 0x1689, "T2-MP3-001", "MP3 player/FM radio/voice recorder 256 Mo flash" } , + { 0x112E, 0x0000, "", "EIDE/hdd and IDE/cd-rom Ctrlr" } , + { 0x112E, 0x000B, "", "EIDE/hdd and IDE/cd-rom Ctrlr" } , + { 0x1130, 0xF211, "0x010", "USB Audio Sound Card" } , + { 0x1131, 0x1131, "Philips Semic", "gthjy" } , + { 0x1131, 0x1131, "7130", "01384E428" } , + { 0x1131, 0x1201, "PTD3000", "VPN IPSEC coprocessor" } , + { 0x1131, 0x1234, "", "EHCI USB 2.0 Controller" } , + { 0x1131, 0x1301, "PTD3210", "SSL Accelerator" } , + { 0x1131, 0x1562, "ISP1561", "EHCI USB 2.0 Controller" } , + { 0x1131, 0x2780, "TDA2780AQ", "TV deflection controller" } , + { 0x1131, 0x3400, "UCB1500", "Modem" } , + { 0x1131, 0x3401, "UCB1500", "Multimedia Audio Device" } , + { 0x1131, 0x5400, "TriMedia TM1000/1100", "Multimedia processor" } , + { 0x1131, 0x5402, "TriMedia TM-1300EH", "Media Processor" } , + { 0x1131, 0x5406, "", "TriMedia PNX1700" } , + { 0x1131, 0x7130, "73c0a1434628", "Philips SAA7135HL Multimedia Capture Device" } , + { 0x1131, 0x7133, "Pinnacle PCTV 110i", "Pinnacle PCTV 110i Capture Device" } , + { 0x1131, 0x7134, "SAA7130", "Hybrid Capture Device" } , + { 0x1131, 0x7145, "d145ah", "ddddf" } , + { 0x1131, 0x7146, "saa7135HL", "PCIVEN_1131&DEV7146" } , + { 0x1131, 0x9730, "SAA9730", "Ethernet controller" } , + { 0x1133, 0x7711, "EiconCard C91", "" } , + { 0x1133, 0x7901, "EiconCard S90", "" } , + { 0x1133, 0x7902, "", "" } , + { 0x1133, 0x7911, "", "" } , + { 0x1133, 0x7912, "", "" } , + { 0x1133, 0x7941, "", "" } , + { 0x1133, 0x7942, "", "" } , + { 0x1133, 0x7943, "", "EiconCard S94" } , + { 0x1133, 0x7944, "", "EiconCard S94" } , + { 0x1133, 0xB921, "", "" } , + { 0x1133, 0xB922, "", "" } , + { 0x1133, 0xB923, "", "EiconCard P92" } , + { 0x1133, 0xE001, "DIVA Pro 2.0 S/T", "" } , + { 0x1133, 0xE002, "DIVA 2.0 S/T", "" } , + { 0x1133, 0xE003, "DIVA Pro 2.0 U", "" } , + { 0x1133, 0xE004, "DIVA 2.0 U", "" } , + { 0x1133, 0xE005, "DIVA 2.01 S/T", "Eicon ISDN card using Siemens IPAC chip" } , + { 0x1133, 0xE00B, "DIVA ISDN 2.02 PCI", "Eicon ISDN card using Infineon chip" } , + { 0x1133, 0xE010, "Maestra", "DIVA Server BRI-2M" } , + { 0x1133, 0xE012, "MaestraQ", "DIVA Server BRI-8M" } , + { 0x1133, 0xE013, "MaestraQ-U", "DIVA Server 4BRI/PCI" } , + { 0x1133, 0xE014, "MaestraP", "DIVA Server PRI-30M" } , + { 0x1133, 0xE015, "", "Diva Server PRI-30M PCI v.2" } , + { 0x1133, 0xE018, "", "DIVA Server BRI-2M/-2F" } , + { 0x1134, 0x0001, "", "Raceway Bridge" } , + { 0x1134, 0x0002, "DPRB", "Dual PCI to RapidIO Bridge" } , + { 0x1135, 0x0001, "", "Printer Cntrlr" } , + { 0x1138, 0x8905, "8905", "STD 32 Bridge" } , + { 0x113C, 0x0000, "PCI9060", "i960 Bridge" } , + { 0x113C, 0x0001, "PCI9060", "i960 Bridge / Evaluation Platform" } , + { 0x113C, 0x0911, "PCI911", "i960Jx I/O Controller" } , + { 0x113C, 0x0912, "PCI912", "i960Cx I/O Controller" } , + { 0x113C, 0x0913, "PCI913", "i960Hx I/O Controller" } , + { 0x113C, 0x0914, "PCI914", "I/O Controller with secondary PCI bus" } , + { 0x113F, 0x0808, "SST-64P", "Adapter" } , + { 0x113F, 0x1010, "SST-128P", "Adapter" } , + { 0x113F, 0x80C0, "", "" } , + { 0x113F, 0x80C4, "", "" } , + { 0x113F, 0x80C8, "", "" } , + { 0x113F, 0x8888, "", "" } , + { 0x113F, 0x9090, "", "" } , + { 0x1141, 0x0001, "", "EIDE/ATAPI super adapter" } , + { 0x1142, 0x3210, "ProMotion 3210", "VGA/AVI Playback Accelerator" } , + { 0x1142, 0x6410, "6410 6422", "GUI Accelerator" } , + { 0x1142, 0x6412, "", "GUI Accelerator" } , + { 0x1142, 0x6420, "", "GUI Accelerator" } , + { 0x1142, 0x6422, "ProMotion-6422", "ProMotion-6422" } , + { 0x1142, 0x6424, "ProVideo 6424", "ProMotion AT24 GUI Accelerator" } , + { 0x1142, 0x6425, "ProMotion AT25", "0752 20005" } , + { 0x1142, 0x6426, "", "GUI Accelerator" } , + { 0x1142, 0x643D, "AT25", "ProMotion-AT3D" } , + { 0x1142, 0x9876, "ProMotion 6422", "139K76B 9808" } , + { 0x1142, 3210, "9809", "139K76B" } , + { 0x1144, 0x0001, "", "Noservo Cntrlr" } , + { 0x1145, 0xF020, "", "CardBus ATAPI Host Adapter" } , + { 0x1145, 0xF021, "NPATA32", "CardBus CompactFlash Adapter" } , + { 0x1145, 0xf024, "NPATA-32", "CardBus CompactFlash Adapter" } , + { 0x1147, 0x1123, "123", "131dq" } , + { 0x1148, 0x4000, "SK-NET", "FDDI adapter" } , + { 0x1148, 0x4200, "", "Token Ring Adapter" } , + { 0x1148, 0x4300, "SysKonnect Genesis", "SK-NET Gigabit Ethernet Adapter" } , + { 0x1148, 0x4320, "Marvell Yukon", "SysKonnect Gigabit Ethernet SK-98xx Version 2.0" } , + { 0x1148, 0x9000, "Marvell Yukon II PCI-X", "PCI-X 10/100/1000Base-T Server" } , + { 0x1148, 0x9E00, "Marvell Yukon EC", "PCI Express 10/100/1000Base-T Desktop" } , + { 0x114A, 0x5565, "VMIPCI-5565", "Ultrahigh-Speed Fiber-Optics Reflective Memory w/ Interrupts" } , + { 0x114A, 0x5579, "VMIPCI-5579", "Reflective Memory Card" } , + { 0x114A, 0x5588, "VMICPCI5588", "VMICPCI5588 Reflective Memory Card" } , + { 0x114A, 0x6504, "", "Timer/SRAM FPGA" } , + { 0x114A, 0x7587, "VMIVME-7587", "" } , + { 0x114D, 0x2189, "0x1002114D", "PCTel HSP56 PCI Modem" } , + { 0x114F, 0x0002, "AccelePort EPC", "" } , + { 0x114F, 0x0003, "RightSwitch SE-6", "" } , + { 0x114F, 0x0004, "AccelePort Xem", "" } , + { 0x114F, 0x0005, "AccelePort Xr", "" } , + { 0x114F, 0x0006, "AccelePort C/X", "" } , + { 0x114F, 0x0007, "DataFire PCI 1 S/T", "Digi Data Fire PCI 1 S/T" } , + { 0x114F, 0x0009, "AccelePort Xr/J", "" } , + { 0x114F, 0x000A, "AccelePort EPC/J", "" } , + { 0x114F, 0x000C, "DataFirePRIme T1", "" } , + { 0x114F, 0x000D, "SyncPort", "X.25/FR 2-port" } , + { 0x114F, 0x0011, "AccelePort8r EIA-232", "" } , + { 0x114F, 0x0012, "AccelePort8r EIA-422", "" } , + { 0x114F, 0x0013, "AccelePort Xr", "" } , + { 0x114F, 0x0014, "AccelePort8r EIA-422", "" } , + { 0x114F, 0x0015, "AccelePort Xem", "" } , + { 0x114F, 0x0016, "AccelePort EPC/X", "" } , + { 0x114F, 0x0017, "AccelePort C/X", "" } , + { 0x114F, 0x0019, "DataFire PCI 1 U", "" } , + { 0x114F, 0x001A, "DataFirePRIme E1", "" } , + { 0x114F, 0x001B, "AccelePort C/X (IBM)", "" } , + { 0x114F, 0x001D, "DataFire RAS", "T1/E1/PRI" } , + { 0x114F, 0x001F, "", "ClydeNonCsu6034" } , + { 0x114F, 0x0020, "", "ClydeNonCsu6032" } , + { 0x114F, 0x0021, "", "ClydeNonCsu4" } , + { 0x114F, 0x0022, "", "ClydeNonCsu2" } , + { 0x114F, 0x0023, "AccelePort RAS", "" } , + { 0x114F, 0x0024, "DataFire RAS B4 ST/U", "" } , + { 0x114F, 0x0026, "AccelePort 4r 920", "" } , + { 0x114F, 0x0027, "AccelePort 8r 920", "" } , + { 0x114F, 0x0029, "DigiClassic PCI", "" } , + { 0x114F, 0x0034, "AccelePort 2r 920", "" } , + { 0x114F, 0x0035, "DataFire DSP", "T1/E1/PRI, Compact PCI" } , + { 0x114F, 0x0040, "AccelePort Xp", "" } , + { 0x114F, 0x0042, "AccelePort 2p PCI", "" } , + { 0x114F, 0x0070, "DataFire Micro V", "" } , + { 0x114F, 0x0071, "DataFire Micro V", "" } , + { 0x114F, 0x0072, "DataFire Micro V", "" } , + { 0x114F, 0x0073, "DataFire Micro V", "" } , + { 0x114F, 0x6001, "Avanstar", "" } , + { 0x1155, 0x0810, "", "486 CPU/PCI Bridge" } , + { 0x1155, 0x0922, "2838", "Pentium CPU/PCI Bridge" } , + { 0x1155, 0x0926, "", "PCI/ISA Bridge" } , + { 0x1158, 0x3011, "", "Tokenet/vg 1001/10m anylan" } , + { 0x1158, 0x9050, "", "Lanfleet/Truevalue" } , + { 0x1158, 0x9051, "", "Lanfleet/Truevalue" } , + { 0x1159, 0x0001, "MV1000", "" } , + { 0x1159, 0x0002, "MV-1500", "Frame Grabber" } , + { 0x115D, 0x0003, "RBEM56G-100", "Cardbus Ethernet 10/100+Modem 56" } , + { 0x115D, 0x0005, "", "CardBus Ethernet 10/100" } , + { 0x115D, 0x0007, "", "CardBus Ethernet 10/100" } , + { 0x115D, 0x000B, "", "CardBus Ethernet 10/100" } , + { 0x115D, 0x000C, "MPCI 3A56GSP-100 PA", "Mini-PCI V.90 56k Modem" } , + { 0x115D, 0x000F, "", "CardBus Ethernet 10/100" } , + { 0x115D, 0x002b, "", "Winmodem built into NEC Versa VXi" } , + { 0x115D, 0x0076, "", "Xircom MPCI3B-56G (Lucent SCORPIO) Soft" } , + { 0x115D, 0x00d3, "2333333333333", "Xircom MPCI Modem 56" } , + { 0x115D, 0x00D4, "MPCI", "Modem 56k" } , + { 0x115D, 0x0101, "", "CardBus 56k Modem" } , + { 0x115D, 0x0103, "", "CardBus Ehternet + 56k Modem" } , + { 0x1161, 0x0001, "", "Host Bridge" } , + { 0x1163, 0x0001, "Verite 1000", "3D Blaster" } , + { 0x1163, 0x2000, "Rendition V2200 (1179-002)", "Rendition V2200 (BLITZ 2200 AGP)" } , + { 0x1165, 0x0001, "", "Motion JPEG rec/play w/audio" } , + { 0x1166, 0x0005, "NB6536 (CNB20-LE)", "PCI to PCI Bridge, bus/dev/func 0/0/1" } , + { 0x1166, 0x0006, "NB6536 (CNB20-HE)", "Host Bridge, function 2 and function 3" } , + { 0x1166, 0x0007, "NB6635 (CNB20-LE/HE)", "CPU to PCI Bridge" } , + { 0x1166, 0x0008, "NB6536 (CNB20-HE)", "Hostbridge & MCH, bus/dev/func 0/0/0" } , + { 0x1166, 0x0009, "NB6536 (CNB20-LE)", "AGP interface" } , + { 0x1166, 0x0010, "CIOB30", "" } , + { 0x1166, 0x0011, "CMIC-HE", "" } , + { 0x1166, 0x0012, "CMIC-LE", "" } , + { 0x1166, 0x0013, "CNB20-HE", "Hostbridge and MCH" } , + { 0x1166, 0x0014, "CNB20-HE", "Host Bridge" } , + { 0x1166, 0x0015, "CMIC-GC", "Hostbridge and MCH" } , + { 0x1166, 0x0016, "CMIC-GC", "Host Bridge" } , + { 0x1166, 0x0017, "CMIC-SL", "" } , + { 0x1166, 0x0101, "CIOB-X2", "" } , + { 0x1166, 0x0103, "BCM5715", "Broadcom dual gigabit, pci bridge" } , + { 0x1166, 0x0110, "CIOB-E", "I/O Bridge with Gigabit Ethernet ServerWorks Grand Champion" } , + { 0x1166, 0x0200, "OSB4", "PCI to ISA Bridge" } , + { 0x1166, 0x0201, "CSB5", "ISA bridge" } , + { 0x1166, 0x0203, "CSB6", "PCI to ISA Bridge" } , + { 0x1166, 0x0211, "OSB4", "EIDE Controller" } , + { 0x1166, 0x0212, "CSB5", "IDE interface" } , + { 0x1166, 0x0213, "OSB6", "PCI EIDE Controller" } , + { 0x1166, 0x0217, "OSB6", "PCI EIDE Controller (Tertiary)" } , + { 0x1166, 0x0220, "OSB4", "OpenHCI Compliant USB Controller" } , + { 0x1166, 0x0221, "OSB6", "OHCI Compliant USB Controller" } , + { 0x1166, 0x0223, "0x0223", "USB controller" } , + { 0x1166, 0x0225, "CSB5", "PCI Bridge" } , + { 0x1166, 0x0227, "CSB6", "PCI Bridge" } , + { 0x1166, 0x0230, "???", "PCI to ISA bridge" } , + { 0x1166, 0x0241, "BC4852", "8-Channel RAIDCore� SATA RAID Host Bus Adapter" } , + { 0x1169, 0x0102, "QL5032", "32 Channel Digital Input Card Interface" } , + { 0x1169, 0x0202, "QL5032", "16 Channel Digital Output, 16 Channel Digital Input Interface" } , + { 0x1169, 0x0302, "QL5032", "32 Channel Analog Input Interface" } , + { 0x1169, 0x0402, "QL5032", "16 Channel Analog Output / Analog Input Interface" } , + { 0x1169, 0x0502, "QL5232", "8 Channel Timer Counter Interface" } , + { 0x1169, 0x0902, "QL5232", "PCI to TigerSHARC FPGA Interface" } , + { 0x1169, 0x2001, "Ql5032-33APQ208C", "PCI to C-DAC RTU bus interface FPGA" } , + { 0x116A, 0x6100, "", "Bus/Tag Channel" } , + { 0x116A, 0x6800, "", "Escon Channel" } , + { 0x116A, 0x7100, "", "Bus/Tag Channel" } , + { 0x116A, 0x7800, "", "Escon Channel" } , + { 0x116E, 0x0015, "VX120", "Fiery EX2000D RIP Card Melbourne VX120" } , + { 0x116E, 0x0500, "Vx500", "Printer ASIC" } , + { 0x1172, 0x0001, "EPF6016ATC144-2", "S CCA5000243A" } , + { 0x1172, 0x0004, "-", "Multi-serial card" } , + { 0x1176, 0x8474, "42000133", "Conexant Multichannel Synchronous Communications Controller (MUSYCC)" } , + { 0x1178, 0xAFA1, "", "Fast Ethernet" } , + { 0x1179, 0x0102, "toshiba america info systems", "Extended PCI IDE Controller" } , + { 0x1179, 0x0103, "", "Extended PCI IDE Controller Type-B" } , + { 0x1179, 0x0179, "0x1179", "pci communication device" } , + { 0x1179, 0x0404, "", "" } , + { 0x1179, 0x0406, "Tecra a2", "Video Capture device" } , + { 0x1179, 0x0407, "", "" } , + { 0x1179, 0x0601, "0555873412", "Toshiba CPU to PCI bridge" } , + { 0x1179, 0x0602, "", "PCI to ISA Bridge for Notebooks" } , + { 0x1179, 0x0603, "ToPIC95", "PCI to CardBus Bridge for Notebooks" } , + { 0x1179, 0x0604, "", "PCI to PCI Bridge for Notebooks" } , + { 0x1179, 0x0605, "", "PCI to ISA Bridge for Notebooks" } , + { 0x1179, 0x0606, "", "PCI to ISA Bridge for Notebooks" } , + { 0x1179, 0x0609, "", "PCI to PCI Bridge for Notebooks" } , + { 0x1179, 0x060A, "ToPIC95B", "Toshiba ToPIC95 CardBus Controller" } , + { 0x1179, 0x060F, "ToPIC97", "CardBus Controller" } , + { 0x1179, 0x0611, "", "PCI to ISA Bridge" } , + { 0x1179, 0x0617, "ToPIC100", "PCI to CardBus Bridge with ZV support" } , + { 0x1179, 0x0618, "", "CPU to PCI and PCI to ISA Bridge" } , + { 0x1179, 0x0701, "vt82c693", "PCI Communication Device" } , + { 0x1179, 0x0804, "0x0804", "Toshiba Smart Media Host Controller" } , + { 0x1179, 0x0805, "PCIVEN_1180&DEV_0592&SUBSYS_828D1033&REV_064&5A9", "SD Card Controller" } , + { 0x1179, 0x0D01, "0x0D01", "FIR Port Type-O" } , + { 0x1179, 0x13A8, "XR17C158/154/152", "Multi-channel PCI UART" } , + { 0x117B, 0x8320, "NOFM12", "USB DEVICE" } , + { 0x117E, 0x0001, "", "Printer Host" } , + { 0x1185, 0x8929, "", "EIDE Controller" } , + { 0x1186, 0x0100, "88e8003", "Ethernet Adapter" } , + { 0x1186, 0x1002, "DFE-550TX/580TX/DFE-550FX", "Fast Ethernet Adapter" } , + { 0x1186, 0x1100, "driv16c003206", "Fast Ethernet Adapter" } , + { 0x1186, 0x1300, "DL10038C or DL10038D (Remark of Realtek RTL-8139)", "Fast Ethernet Adapter" } , + { 0x1186, 0x1301, "DGE-528T ", "Fast Ethernet Adapter" } , + { 0x1186, 0x1340, "DFE-690TXD", "CardBus PC Card" } , + { 0x1186, 0x1561, "DRP-32TXD", "CardBus PC Card" } , + { 0x1186, 0x3065, "14001186", "D-Link DFE-500Tx PCI fast Ethernet adapter Rev.A" } , + { 0x1186, 0x3106, "DFE 530TX+ rev E1", "Fast Ethernet Adapter" } , + { 0x1186, 0x3300, "D-Link Air Wireless Network (DWL-G510)", "IEEE 802.11g PCI card" } , + { 0x1186, 0x3b00, "0x3b001186", "D-LINK DWL-650+" } , + { 0x1186, 0x3c09, "DWL-G510 Version C1", "Ralink RT61" } , + { 0x1186, 0x4000, "DL2000", "Gigabit Ethernet Adapter" } , + { 0x1186, 0x4001, "DFE-650TX", "D Link Fast Ethernet PCMCIA Card" } , + { 0x1186, 0x4300, "dlg10028", "Used on DGE-528T Gigabit adaptor" } , + { 0x1186, 0x4B01, "DGE-530T", "Gigabit Ethernet Adapter" } , + { 0x1186, 0x4C00, "DGE-530T", "Gigabit Ethernet Adapter" } , + { 0x1189, 0x1592, "", "VL/PCI Bridge" } , + { 0x118C, 0x0014, "PCIB", "C-bus II to PCI bus host bridge chip" } , + { 0x118C, 0x1117, "MAC-94C201B3", "Corollary/Intel Memory Controller Chip" } , + { 0x118D, 0x0001, "n/a", "Raptor-PCI framegrabber" } , + { 0x118D, 0x0012, "Model 12", "Road Runner Frame Grabber" } , + { 0x118D, 0x0014, "Model 14", "Road Runner Frame Grabber" } , + { 0x118D, 0x0024, "Model 24", "Road Runner Frame Grabber" } , + { 0x118D, 0x0044, "Model 44", "Road Runner Frame Grabber" } , + { 0x118D, 0x0112, "Model 12", "Road Runner Frame Grabber" } , + { 0x118D, 0x0114, "Model 14", "Road Runner Frame Grabber" } , + { 0x118D, 0x0124, "Model 24", "Road Runner Frame Grabber" } , + { 0x118D, 0x0144, "Model 44", "Road Runner Frame Grabber" } , + { 0x118D, 0x0212, "Model 12", "Road Runner Frame Grabber" } , + { 0x118D, 0x0214, "Model 14", "Road Runner Frame Grabber" } , + { 0x118D, 0x0224, "Model 24", "Road Runner Frame Grabber" } , + { 0x118D, 0x0244, "Model 44", "Road Runner Frame Grabber" } , + { 0x118D, 0x0312, "Model 12", "Road Runner Frame Grabber" } , + { 0x118D, 0x0314, "Model 14", "Road Runner Frame Grabber" } , + { 0x118D, 0x0324, "Model 24", "Road Runner Frame Grabber" } , + { 0x118D, 0x0344, "Model 44", "Road Runner Frame Grabber" } , + { 0x118E, 0x0042, "", "" } , + { 0x118E, 0x0142, "", "" } , + { 0x118E, 0x0242, "", "" } , + { 0x118E, 0x0342, "", "" } , + { 0x118E, 0x0440, "", "" } , + { 0x118E, 0x0442, "", "" } , + { 0x118E, 0x0842, "", "" } , + { 0x1191, 0x0001, "", "IDE Ctrlr" } , + { 0x1191, 0x0002, "ATP850UF", "UltraDMA33 EIDE Controller (AEC6210UF)" } , + { 0x1191, 0x0003, "", "SCSI-2 cache Cntrlr" } , + { 0x1191, 0x0004, "ATP8400", "UltraDMA33 EIDE Controller" } , + { 0x1191, 0x0005, "ATP850UF", "UltraDMA33 EIDE Controller (AEC6210UF)" } , + { 0x1191, 0x0006, "ATP860A", "UltraDMA66 EDIE Controller (AEC6260)" } , + { 0x1191, 0x0007, "ATP860R", "UltraDMA66 EIDE Controller (AEC6260)" } , + { 0x1191, 0x0008, "ATP865", "2CH PCI UltraDMA133 IDE Controller" } , + { 0x1191, 0x0009, "ATP865", "2CH PCI UltraDMA133 IDE Controller" } , + { 0x1191, 0x000a, "aec6885", "ACARD AEC-6885/6895/6896 RAID Controller" } , + { 0x1191, 0x000B, "AEC6897/6898", "ACARD AEC-6897/6898 RAID Controller" } , + { 0x1191, 0x000D, "ATP8620", "2S1P PCI-X SATA(3G)/UDMA Combo Controller" } , + { 0x1191, 0x8001, "ATP8600", "SCSI-2 RAID (cache?) Adapter (AEC6820U)" } , + { 0x1191, 0x8002, "ATP850S", "SCSI-2 Host Adapter (AEC6710L/F/s)" } , + { 0x1191, 0x8010, "ATP870", "Ultra Wide SCSI Controller" } , + { 0x1191, 0x8020, "ATP870", "Ultra SCSI Controller" } , + { 0x1191, 0x8030, "ATP870", "Ultra SCSI Controller" } , + { 0x1191, 0x8040, "ATP870", "SCSI Controller" } , + { 0x1191, 0x8050, "", "Ultra Wide SCSI Controller" } , + { 0x1191, 0x8060, "AEC671x", "SCSI Host Adapter" } , + { 0x1191, 0x8081, "AEC-67160", "PCI Ultra160 LVD/SE SCSI Adapter" } , + { 0x1191, 0x808A, "ATP885", "AEC67162 PCI Ultra3 LVD/SE Controller" } , + { 0x1197, 0x010C, "CompuScope 82G", "8-bit 2GS/s Analog Input Card" } , + { 0x1199, 0x0001, "", "IRMA 3270 PCI Adapter" } , + { 0x1199, 0x0002, "", "Advanced ISCA PCI Adapter" } , + { 0x1199, 0x0201, "", "SDLC PCI Adapter" } , + { 0x119B, 0x1221, "82C092G", "PCI PCMCIA bridge" } , + { 0x119E, 0x0001, "MB86697", "FireStream 155 ATM adapter" } , + { 0x119E, 0x0003, "MB86695", "FireStream 50 ATM adapter" } , + { 0xECC0, 0x0050, "", "" } , + { 0xECC0, 0x0051, "", "" } , + { 0xECC0, 0x0060, "", "" } , + { 0xECC0, 0x0070, "", "" } , + { 0xECC0, 0x0071, "", "" } , + { 0xECC0, 0x0072, "", "" } , + { 0xECC0, 0x0080, "", "" } , + { 0x11A8, 0x7302, "", "NTX-8023-PCI 2MB Long Card" } , + { 0x11A8, 0x7308, "", "NTX-8023-PCI 8MB Long Card" } , + { 0x11A8, 0x7402, "", "NTX-8023-PCI 2MB Short Card" } , + { 0x11A8, 0x7408, "", "NTX-8023-PCI 8MB Short Card" } , + { 0x11A9, 0x4240, "AMCC S5933Q", "pci matchmaker 9622qac" } , + { 0x11AB, 0x0146, "GT-64010/A", "System Ctrlr for R4xxx/5000 Family CPUs" } , + { 0x11AB, 0x11AB, "88E8055 PCI-E", "Gigabit Ethernet Controler" } , + { 0x11AB, 0x11AB, "88E8055", "Marvell Yukon 88E8055 PCI-E Gigabit Ethernet Controller" } , + { 0x11AB, 0x13F8, "W8300", "802.11 Adapter" } , + { 0x11AB, 0x1fa6, "88W8300", "The Libertas WLAN 802.11b/g" } , + { 0x11AB, 0x1FA7, "00000000", "Libertas WLAN 802.11b/g" } , + { 0x11AB, 0x1FAA, "8335", "Marvell Libertas 802.11b/g Wireless (8335)" } , + { 0x11AB, 0x2A30, "88W8687", "PCI-Express 802.11bg Wireless" } , + { 0x11AB, 0x4320, "88E8058", "Marvell Yukon PCI E Gigabit" } , + { 0x11AB, 0x4350, "88E8036", "Yukon PCI-E Fast Ethernet Controller" } , + { 0x11AB, 0x4351, "88E8038", "Yukon PCI-E Fast Ethernet Controller" } , + { 0x11AB, 0x4352, "88E8038", "Marvell Yukon 88E8038 PCI-E Fast Ethernet Controller" } , + { 0x11AB, 0x4353, "88E8039 - http://www.marvell.com/drivers/driverDis", "Gigabit" } , + { 0x11AB, 0x4354, "88E8040", "Marvell Yukon 88E8040 PCI-E Fast Ethernet Controller" } , + { 0x11AB, 0x4355, "88E8040T", "Marvell Yukon 88E8040T PCI-E Fast Ethernet Controller" } , + { 0x11AB, 0x4360, "88E8050", "Yukon PCI-E ASF Gigabit Ethernet Controller" } , + { 0x11AB, 0x4361, "88E8036", "Marvell Yukon -EC 88E8036 PCI Express Fast Ethernet Controller" } , + { 0x11AB, 0x4362, "88E8053", "Marvell Yukon 88E8053 PCI-E Gigabit Ethernet Controller" } , + { 0x11AB, 0x4363, "88E8053", "Yukon PCI-E Gigabit Ethernet Controller" } , + { 0x11AB, 0x4364, "88E8056", "Yukon PCI-E Gigabit Ethernet Controller" } , + { 0x11AB, 0x4365, "88E8070", "Yukon Gigabit Controller" } , + { 0x11AB, 0x436A, "88E8058", "Marvell Yukon 88E8058" } , + { 0x11AB, 0x436b, "88E8072", "Gigabit Ethernet" } , + { 0x11AB, 0x4611, "GT-64115", "System Controller" } , + { 0x11AB, 0x4620, "GT-64120", "System Controller for R5000 & R7000 (64-bit PCI)" } , + { 0x11AB, 0x4801, "GT-48001", "8 port switched ethernet ctrlr" } , + { 0x11AB, 0x4809, "EV-48300", "Evaluation board for the GT-48300" } , + { 0x11AB, 0x5005, "F5D5005", "Belkin Desktop Gigabit PCI card" } , + { 0x11AB, 0x5040, "88SX5040", "4-port SATA I PCI-X Controller" } , + { 0x11AB, 0x5041, "88SX504", "4-port SATA I PCI-X Controller" } , + { 0x11AB, 0x5080, "RocketRAID 182x", "SATA Controller" } , + { 0x11AB, 0x5081, "RocketRAID 182x", "SATA Controller" } , + { 0x11AB, 0x6041, "MV88SX6041", "Marvell Technology Group Ltd. MV88SX6041 4-port SATA II PCI-X Controller (rev 03)" } , + { 0x11AB, 0x6081, "?", "SATA II PCI-X Controller" } , + { 0x11AB, 0x6101, "88SE6101", "PATA 133 One Channel" } , + { 0x11AB, 0x6111, "?", "61xx RAID" } , + { 0x11AB, 0x6120, "?", "61xx RAID" } , + { 0x11AB, 0x6121, "88SE6121", "61xx RAID" } , + { 0x11AB, 0x6122, "?", "61xx RAID" } , + { 0x11AB, 0x6140, "?", "61xx RAID" } , + { 0x11AB, 0x6145, "88SE6145", "Add-on IC to provide 4x SATA Ports, attached to ICH7 (SthBridge?) via PCI-Express." } , + { 0x11AB, 0x6320, "GT-64130/131", "System Controller for PowerPC Processors" } , + { 0x11AB, 0x6440, "?", "64xx/63xx SAS" } , + { 0x11AB, 0x6480, "?", "64xx/63xx SAS" } , + { 0x11AB, 0x6485, "MV6446x", "System Controller for PowerPC Processors, Revision B" } , + { 0x11AB, 0x9653, "GT-96100A", "Advanced Communication Controller" } , + { 0x11AB, 0xF003, "GT-64010", "Primary Image Piranha Image Generator" } , + { 0x11AB, 0xF004, "GT64120", "Primary Image Barracuda Image Generator" } , + { 0x11AB, 0xF006, "GT-64120A", "Primary Image Cruncher Geometry Accelerator" } , + { 0x11AB, 0xFFFF, "88SA8040", "PATA2SATA/SATA2PATA Bridge" } , + { 0x11AD, 0x0001, "LC82C168?", "Fast Ethernet Adapter" } , + { 0x11AD, 0x0002, "LC82C169C", "NETGEAR FA310TX Fast Ethernet PCI Adapter" } , + { 0x11AD, 0xC115, "LC82C115", "PNIC II PCI MAC/PHY" } , + { 0x11AE, 0x4153, "", "Bridge Controller" } , + { 0x11AE, 0x5842, "", "Bridge Controller" } , + { 0x11AF, 0x0001, "9704", "Cinema" } , + { 0x11AF, 0x000A, " ", "Nitris" } , + { 0x11AF, 0x000B, " ", "Nitris DX / Mojo DX" } , + { 0x11B0, 0x0001, "V960PBC/PSC", "i960 Local Bus to PCI Bridge" } , + { 0x11B0, 0x0002, "V961PBC/PSC", "i960Jx Local Bus to PCI Bridge" } , + { 0x11B0, 0x0004, "V962PBC/PSC", "i960Cx/Hx Local Bus to PCI Bridge" } , + { 0x11B0, 0x0010, "V292PBC/PSC", "Am29K Local Bus to PCI Bridge" } , + { 0x11B0, 0x0021, "V363EPC", "i960Sx Local Bus to PCI Bridge" } , + { 0x11B0, 0x0022, "V363EPC", "i960Jx Local Bus to PCI Bridge" } , + { 0x11B0, 0x0024, "V363EPC", "i960Cx/Hx Local Bus to PCI Bridge" } , + { 0x11B0, 0x0030, "V363EPC", "Am29K Local Bus to PCI Bridge" } , + { 0x11B0, 0x0100, "V320USC", "PCI System Ctrlr for 32-bit MIPS CPU" } , + { 0x11B0, 0x0101, "V320USC", "PCI System Ctrlr for 32-bit MIPS CPU" } , + { 0x11B0, 0x0102, "V320USC", "PCI System Ctrlr for Super-H SH3 CPU" } , + { 0x11B0, 0x0103, "V320USC", "PCI System Ctrlr for Super-H SH4 CPU" } , + { 0x11B0, 0x0200, "V370PDC", "High Performance PCI SDRAM Controller" } , + { 0x11B0, 0x0292, "V292PBC", "Am29030/40 Bridge" } , + { 0x11B0, 0x0500, "V340HPC", "PCI System Ctrlr for 64-bit MIPS CPU" } , + { 0x11B0, 0x0960, "V96xPBC", "i960 Bridges for i960 Processors" } , + { 0x11B0, 0xC960, "V96DPC", "i960 Dual PCI Bridge" } , + { 0x11B5, 0x0001, "PMC/PMX1553", "1553 Bus Interface Card" } , + { 0x11B5, 0x0002, "PMCF1", "FLASH memory Card" } , + { 0x11B5, 0x0003, "PMCMMA", "Multi Media Adapter" } , + { 0x11B5, 0x0004, "PMCVGO", "Video Graphics Overlay" } , + { 0x11B5, 0x0005, "PMCPCIS", "PPzero Slave Interface Card" } , + { 0x11B5, 0x0006, "PMCPCIM", "PPzero Master Interface Card" } , + { 0x11B5, 0x0007, "PMCQ1", "Serial/1553 Interface Card" } , + { 0x11B5, 0x0008, "EPMCQ2", "Intelligent Serial/Ethernet Card" } , + { 0x11B5, 0x0009, "PMCPIO1", "Parallel I/O Module" } , + { 0x11B5, 0x000a, "PMCFA1C", "Fibre Channel Adapter" } , + { 0x11B5, 0x000b, "PMCHH1", "High Speed DSP Gateway Module" } , + { 0x11B5, 0x000c, "PMCMA2", "Memory Adaptor Module" } , + { 0x11B5, 0x0012, "PMCF1", "FLASH memory Card (V2)" } , + { 0x11B5, 0x0013, "PMC1553EX", "1553 Bus Interface Card" } , + { 0x11B5, 0x0014, "PMC1553E", "1553 Bus Interface Card" } , + { 0x11B5, 0x2200, "PMCFA2C", "Dual Fibre Channel Adapter" } , + { 0x0070, 0x6800, " ", "Hauppage Nova -TD-500 DVB-T Tuner Device" } , + { 0x11B8, 0x0001, "Quad PeerMaster", "" } , + { 0x11B9, 0xC0ED, "SSA Ctrlr", "" } , + { 0x11BC, 0x0001, "NPI NuCard", "PCI FDDI" } , + { 0x11BD, 0x0015, "660806-2.0", "rob2d" } , + { 0x11BD, 0xBEBE, "51011810", "pinnacle, bendino V1.0A | Studio MovieBoard 500-PCI V.10" } , + { 0x11BD, 0xBEDE, "51016494", "MB87J3560" } , + { 0x11C1, 0x0440, "LT Winmodem 56k", "Data+Fax+Voice+DSVD" } , + { 0x11C1, 0x0441, "4390143", "modem driver" } , + { 0x11C1, 0x0442, "1648T00", "LT WinModem 56K Data+Fax" } , + { 0x11C1, 0x0443, "LT Winmodem", "1646T00" } , + { 0x11C1, 0x0444, "LT Winmodem", "845G" } , + { 0x11C1, 0x0445, "LT Winmodem", "" } , + { 0x11C1, 0x0446, "LT Winmodem", "" } , + { 0x11C1, 0x0447, "LT Winmodem", "windowsme" } , + { 0x11C1, 0x0448, "LT Winmodem 56k", "SV2P2" } , + { 0x11C1, 0x0449, "LT Winmodem 56k", "0449144F" } , + { 0x11C1, 0x044A, "LT Winmodem 56k", "" } , + { 0x11C1, 0x044B, "LT Winmodem", "" } , + { 0x11C1, 0x044C, "LT Winmodem", "9M56PML-G" } , + { 0x11C1, 0x044D, "LT Winmodem", "" } , + { 0x11C1, 0x044E, "12232", "LT WinModem 56k Data+Fax or Agere F-1156IV/A3" } , + { 0x11C1, 0x044F, "90094-1", "LT V.90+DSL WildFire Modem" } , + { 0x11C1, 0x0450, "1456VQH19R-1(INT)", "LT Winmodem 56K" } , + { 0x11C1, 0x0451, "LT Winmodem", "LT WinModem 56k Data+Fax+Voice+DSVD" } , + { 0x11C1, 0x0452, "LT Winmodem", "1513144" } , + { 0x11C1, 0x0453, "LT Winmodem", "" } , + { 0x11C1, 0x0454, "LT Winmodem", "" } , + { 0x11C1, 0x0455, "LT Winmodem", "" } , + { 0x11C1, 0x0456, "LT Winmodem", "" } , + { 0x11C1, 0x0457, "LT Winmodem", "" } , + { 0x11C1, 0x0458, "1648C", "Mars 3 Mercury v.92 v.44" } , + { 0x11C1, 0x0459, "LT Winmodem", "" } , + { 0x11C1, 0x045A, "LT Winmodem", "" } , + { 0x11C1, 0x045D, "LT WinModem", "mars2" } , + { 0x11C1, 0x0461, "", "V90 Wildfire Modem" } , + { 0x11C1, 0x0462, "1690", "56K.V90/ADSL Wildwire Modem" } , + { 0x11C1, 0x0464, "This is NOT a Riptide! (as previously stated)", "Lucent Wildwire v.90 + DSL modem" } , + { 0x11C1, 0x0480, "Venus Winmodem", "56k.V90/ADSL Wildfire Modem" } , + { 0x11C1, 0x048b, "1648T00", "creative modem blaster di5733-1" } , + { 0x11C1, 0x048C, "1648c-tv5", "creative modem blaster di5733-1" } , + { 0x11C1, 0x048E, "svp92pl-t00", "56k V.92modem" } , + { 0x11C1, 0x048F, "SV92P-T00", "Agere PCI Soft Modem. SV92PL" } , + { 0x11C1, 0x0540, "", "" } , + { 0x11C1, 0x0600, "sv92p2", "SV92P-T00 Agere PCI Soft Modem. SV92PL" } , + { 0x11C1, 0x0620, "SV92PP", "Agere PCI Soft Modem for linux unbuntu" } , + { 0x11C1, 0x1040, "Prespa", "Agere Systems HDA Modem" } , + { 0x11C1, 0x3026, "0x11c13026", "Agere Systems HDA Modem" } , + { 0x11C1, 0x5400, "OR3TP12", "FPSC FPGA with 32/64bit, 33/66MHz core" } , + { 0x11C1, 0x5801, "", "USB Open Host Controller" } , + { 0x11C1, 0x5802, "USS-312MC", "2-port PCI-to-USB OpenHCI Host Ctrlr" } , + { 0x11C1, 0x5803, "USS-344", "QuadraBus 4-port USB OpenHCI Host Ctrlr" } , + { 0x11C1, 0x5805, "uss344", "USB Advanced Host Controller" } , + { 0x11C1, 0x5811, "FW322", "1394A PCI PHY/Link Open Host Ctrlr I/F" } , + { 0x11C1, 0x5901, "unknown", "firewire chip for macbook pro" } , + { 0x11C1, 0x9876, "lucent 1646T00", "LT WinModem 56K Data+Fax" } , + { 0x11C1, 0xAB20, "WaveLAN", "PCI Wireless LAN Adapter" } , + { 0x11C1, 0xAB30, "Hermes2?", "Mini-PCI WaveLAN a/b/g" } , + { 0x11C1, 0xED00, "ET-131x", "PCI-E Ethernet Controller" } , + { 0x11C1, 7121, "", "" } , + { 0x11C6, 0x3001, "1", "VM-1200 Opto Unit Controller" } , + { 0x11C8, 0x0658, "PSB 32", "32 bit , 33 Mhz PCI-SCI Bridge" } , + { 0x11C8, 0xD665, "PSB64", "64 bit , 33 Mhz PCI-SCI Bridge" } , + { 0x11C8, 0xD667, "PSB66", "64 bit , 66 Mhz PCI-SCI Bridge. (D33x)" } , + { 0x11C9, 0x0010, "", "16-line serial port w/DMA" } , + { 0x11C9, 0x0011, "", "4-line serial port w/DMA" } , + { 0x11CB, 0x2000, "PCI-9050-1100083-11", "port small IC" } , + { 0x11CB, 0x4000, "SUPI-1", "XIO/SIO Host" } , + { 0x11CB, 0x8000, "T225", "Bridge RIO Host" } , + { 0x11CE, 0x102B, "1001", "FF00102B" } , + { 0x11D1, 0x01F7, "VxP524", "PCI Video Processor" } , + { 0x11D1, 0x01F8, "VxP524", "PCI Video Processor" } , + { 0x11D1, 0x01f9, "rev_03", "tuner card" } , + { 0x11D1, 0x1520, "tag4769", "Video card" } , + { 0x11D4, 0x1535, "ADSP-21535", "Blackfin DSP PCI Bus Interface" } , + { 0x11D4, 0x1805, "62412-51", "U35545.2-0.6" } , + { 0x11D4, 0x1884, "AD1884HD", "SoundMAX Integrated Digital HD Audio" } , + { 0x11D4, 0x1889, "AD1980", "Sound Chip" } , + { 0x11D4, 0x1981, "AD1981HD", "SoundMAX Integrated Digital HD Audio" } , + { 0x11D4, 0x1983, "AD1983HD", "SoundMAX Integrated Digital HD Audio" } , + { 0x11D4, 0x1984, "Analog Devices ADI 198x", "Analog Devices ADI 198x Integrated HD Audio" } , + { 0x11D4, 0x1986, "AD198b", "SoundMAX Integrated Digital HD Audio" } , + { 0x11D4, 0x198B, "AD1988B", "AD1988B HD Audio CODEC" } , + { 0x11D4, 0x2192, "ADSP-2192", "DSP Microcomputer (function #0)" } , + { 0x11D4, 0x219A, "ADSP-2192", "DSP Microcomputer (function #1)" } , + { 0x11D4, 0x219E, "ADSP-2192", "DSP Microcomputer (function #2)" } , + { 0x11D4, 0x2F44, "ADSP-2141", "SafeNet Crypto Accelerator chip" } , + { 0x11D5, 0x0115, "10115", "Versatec Parallel Interface (VPI) + Centronics" } , + { 0x11D5, 0x0116, "10118", "DR11-W emulator" } , + { 0x11D5, 0x0117, "10117", "Versatec Parallel Interface (VPI) + Centronics" } , + { 0x11D5, 0x0118, "10118", "DR11-W emulator" } , + { 0x1234, 0x1111, "BGE", "VGA BIOS Extensions Graphics Adapter" } , +} ; + + +// Use this value for loop control during searching: +#define PCI_DEVTABLE_LEN (sizeof(PciDevTable)/sizeof(PCI_DEVTABLE)) + +typedef struct _PCI_CLASSCODETABLE +{ + unsigned char BaseClass ; + unsigned char SubClass ; + unsigned char ProgIf ; + const char * BaseDesc ; + const char * SubDesc ; + const char * ProgDesc ; +} PCI_CLASSCODETABLE, *PPCI_CLASSCODETABLE ; + +PCI_CLASSCODETABLE PciClassCodeTable [] = +{ + { 0x00, 0x00, 0x00, "Pre-2.0 PCI Specification Device", "Non-VGA","" } , + { 0x00, 0x01, 0x00, "Pre-2.0 PCI Specification Device", "VGA Compatible", "" } , + + { 0x01, 0x00, 0x00, "Mass Storage Controller", "SCSI", "" } , + { 0x01, 0x01, 0x00, "Mass Storage Controller", "IDE", "" } , + { 0x01, 0x02, 0x00, "Mass Storage Controller", "Floppy", "" } , + { 0x01, 0x03, 0x00, "Mass Storage Controller", "IPI", "" } , + { 0x01, 0x04, 0x00, "Mass Storage Controller", "RAID", "" } , + { 0x01, 0x80, 0x00, "Mass Storage Controller", "Other", "" } , + + { 0x02, 0x00, 0x00, "Network Controller", "Ethernet", "" } , + { 0x02, 0x01, 0x00, "Network Controller", "Token Ring", "" } , + { 0x02, 0x02, 0x00, "Network Controller", "FDDI", "" } , + { 0x02, 0x03, 0x00, "Network Controller", "ATM", "" } , + { 0x02, 0x80, 0x00, "Network Controller", "Other", "" } , + + { 0x03, 0x00, 0x00, "Display Controller", "PC Compatible", "VGA" } , + { 0x03, 0x00, 0x01, "Display Controller", "PC Compatible", "8514" } , + { 0x03, 0x01, 0x00, "Display Controller", "XGA", "" } , + { 0x03, 0x80, 0x00, "Display Controller", "Other", "" } , + + { 0x04, 0x00, 0x00, "Multimedia Device", "Video", "" } , + { 0x04, 0x01, 0x00, "Multimedia Device", "Audio", "" } , + { 0x04, 0x80, 0x00, "Multimedia Device", "Other", "" } , + + { 0x05, 0x00, 0x00, "Memory Controller", "RAM", "" } , + { 0x05, 0x01, 0x00, "Memory Controller", "Flash", "" } , + { 0x05, 0x80, 0x00, "Memory Controller", "Other", "" } , + + { 0x06, 0x00, 0x00, "Bridge Device", "Host/PCI", "" } , + { 0x06, 0x01, 0x00, "Bridge Device", "PCI/ISA", "" } , + { 0x06, 0x02, 0x00, "Bridge Device", "PCI/EISA", "" } , + { 0x06, 0x03, 0x00, "Bridge Device", "PCI/Micro Channel", "" } , + { 0x06, 0x04, 0x00, "Bridge Device", "PCI/PCI", "" } , + { 0x06, 0x05, 0x00, "Bridge Device", "PCI/PCMCIA", "" } , + { 0x06, 0x06, 0x00, "Bridge Device", "PCI/NuBus", "" } , + { 0x06, 0x07, 0x00, "Bridge Device", "PCI/CardBus", "" } , + { 0x06, 0x80, 0x00, "Bridge Device", "Other", "" } , + + { 0x07, 0x00, 0x00, "Simple Communications Controller", "Serial", "Generic XT Compatible" } , + { 0x07, 0x00, 0x01, "Simple Communications Controller", "Serial", "16450 Compatible" } , + { 0x07, 0x00, 0x02, "Simple Communications Controller", "Serial", "16550 Compatible" } , + { 0x07, 0x01, 0x00, "Simple Communications Controller", "Parallel", "Standard" } , + { 0x07, 0x01, 0x00, "Simple Communications Controller", "Parallel", "Bidirectional" } , + { 0x07, 0x01, 0x01, "Simple Communications Controller", "Parallel", "ECP 1.X Compliant" } , + { 0x07, 0x80, 0x02, "Simple Communications Controller", "Other", "" } , + + { 0x08, 0x00, 0x00, "Base Systems Peripheral", "PIC (Programmable Interrupt Controller)", "Generic 8259" } , + { 0x08, 0x00, 0x01, "Base Systems Peripheral", "PIC (Programmable Interrupt Controller)", "ISA" } , + { 0x08, 0x00, 0x02, "Base Systems Peripheral", "PIC (Programmable Interrupt Controller)", "PCI" } , + { 0x08, 0x01, 0x00, "Base Systems Peripheral", "DMA (Direct Memory Access)", "Generic 8259" } , + { 0x08, 0x01, 0x01, "Base Systems Peripheral", "DMA (Direct Memory Access)", "ISA" } , + { 0x08, 0x01, 0x02, "Base Systems Peripheral", "DMA (Direct Memory Access)", "EISA" } , + { 0x08, 0x02, 0x00, "Base Systems Peripheral", "System Timer", "Generic 8259" } , + { 0x08, 0x02, 0x01, "Base Systems Peripheral", "System Timer", "ISA" } , + { 0x08, 0x02, 0x02, "Base Systems Peripheral", "System Timer", "EISA" } , + { 0x08, 0x03, 0x00, "Base Systems Peripheral", "RTC (Real Time Clock)", "Generic" } , + { 0x08, 0x03, 0x01, "Base Systems Peripheral", "RTC (Real Time Clock)", "ISA" } , + { 0x08, 0x80, 0x00, "Base Systems Peripheral", "Other", "" } , + + { 0x09, 0x00, 0x00, "Input Device", "Keyboard", "" } , + { 0x09, 0x01, 0x00, "Input Device", "Digitizer (Pen)", "" } , + { 0x09, 0x02, 0x00, "Input Device", "Mouse", "" } , + { 0x09, 0x80, 0x00, "Input Device", "Other", "" } , + + { 0x0A, 0x00, 0x00, "Docking Station", "Generic", "" } , + { 0x0A, 0x80, 0x00, "Docking Station", "Other", "" } , + + { 0x0B, 0x00, 0x00, "Processor", "i386", "" } , + { 0x0B, 0x01, 0x00, "Processor", "i486", "" } , + { 0x0B, 0x02, 0x00, "Processor", "Pentium", "" } , + { 0x0B, 0x10, 0x00, "Processor", "Alpha", "" } , + { 0x0B, 0x20, 0x00, "Processor", "Power PC", "" } , + { 0x0B, 0x80, 0x00, "Processor", "Co-processor", "" } , + + { 0x0C, 0x00, 0x00, "Serial Bus Controller", "Firewire (IEEE 1394)", "" } , + { 0x0C, 0x01, 0x00, "Serial Bus Controller", "ACCESS.bus", "" } , + { 0x0C, 0x02, 0x00, "Serial Bus Controller", "SSA (Serial Storage Archetecture)", "" } , + { 0x0C, 0x03, 0x00, "Serial Bus Controller", "USB (Universal Serial Bus)", "" } , + { 0x0C, 0x04, 0x00, "Serial Bus Controller", "Fibre Channel", "" } , + + { 0xFF, 0x00, 0x00, "Unknown", "Device Does Not Fit In Class Codes", "UDF" } , +} ; + +// Use this value for loop control during searching: +#define PCI_CLASSCODETABLE_LEN (sizeof(PciClassCodeTable)/sizeof(PCI_CLASSCODETABLE)) + +const char * PciCommandFlags [] = +{ + "I/O Access", + "Memory Access", + "Bus Mastering", + "Special Cycles", + "Memory Write & Invalidate", + "Palette Snoop", + "Parity Errors", + "Wait Cycles", + "System Errors", + "Fast Back-To-Back", + "Reserved 10", + "Reserved 11", + "Reserved 12", + "Reserved 13", + "Reserved 14", + "Reserved 15" +} ; + +// Use this value for loop control during searching: +#define PCI_COMMANDFLAGS_LEN (sizeof(PciCommandFlags)/sizeof(char *)) + + +const char * PciStatusFlags [] = +{ + "Reserved 0", + "Reserved 1", + "Reserved 2", + "Reserved 3", + "Reserved 4", + "66 MHz Capable", + "User-Defined Features", + "Fast Back-To-Back", + "Data Parity Reported", + "", + "", + "Signalled Target Abort", + "Received Target Abort", + "Received Master Abort", + "Signalled System Error", + "Detected Parity Error" +} ; + +// Use this value for loop control during searching: +#define PCI_STATUSFLAGS_LEN (sizeof(PciStatusFlags)/sizeof(char *)) + + +const char * PciDevSelFlags [] = +{ + "Fast Devsel Speed", // TypeC + "Medium Devsel Speed", // TypeB + "Slow Devsel Speed", // TypeA + "Reserved 9&10" +} ; + +// Use this value for loop control during searching: +#define PCI_DEVSELFLAGS_LEN (sizeof(PciDevSelFlags)/sizeof(char *)) + diff --git a/kernel/include/pipe.h b/kernel/include/pipe.h new file mode 100644 index 00000000..e2de45f7 --- /dev/null +++ b/kernel/include/pipe.h @@ -0,0 +1,27 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * Pipe + */ + +#pragma once + +#include + +typedef struct _pipe_device { + uint8_t * buffer; + size_t write_ptr; + size_t read_ptr; + size_t size; + size_t refcount; + volatile int lock_read[2]; + volatile int lock_write[2]; + list_t * wait_queue_readers; + list_t * wait_queue_writers; + int dead; + list_t * alert_waiters; +} pipe_device_t; + +fs_node_t * make_pipe(size_t size); +int pipe_size(fs_node_t * node); +int pipe_unsize(fs_node_t * node); + diff --git a/kernel/include/printf.h b/kernel/include/printf.h new file mode 100644 index 00000000..37ff085e --- /dev/null +++ b/kernel/include/printf.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +extern size_t vasprintf(char * buf, const char *fmt, va_list args); +extern int sprintf(char *buf, const char *fmt, ...); +extern int fprintf(fs_node_t * device, char *fmt, ...); + diff --git a/kernel/include/process.h b/kernel/include/process.h new file mode 100644 index 00000000..322f88fc --- /dev/null +++ b/kernel/include/process.h @@ -0,0 +1,156 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ + +#pragma once + +//#include +#include +#include +#include + +#define KERNEL_STACK_SIZE 0x8000 + +typedef signed int pid_t; +typedef unsigned int user_t; +typedef unsigned char status_t; + +#define USER_ROOT_UID (user_t)0 + +/* Unix waitpid() options */ +enum wait_option{ + WCONTINUED, + WNOHANG, + WUNTRACED +}; + +/* x86 task */ +typedef struct thread { + uintptr_t esp; /* Stack Pointer */ + uintptr_t ebp; /* Base Pointer */ + uintptr_t eip; /* Instruction Pointer */ + + uint8_t fpu_enabled; + uint8_t fp_regs[512]; + + uint8_t padding[32]; /* I don't know */ + + page_directory_t * page_directory; /* Page Directory */ +} thread_t; + +/* Portable image struct */ +typedef struct image { + size_t size; /* Image size */ + uintptr_t entry; /* Binary entry point */ + uintptr_t heap; /* Heap pointer */ + uintptr_t heap_actual; /* Actual heap location */ + uintptr_t stack; /* Process kernel stack */ + uintptr_t user_stack; /* User stack */ + uintptr_t start; + uintptr_t shm_heap; + volatile int lock[2]; +} image_t; + +/* Resizable descriptor table */ +typedef struct descriptor_table { + fs_node_t ** entries; + size_t length; + size_t capacity; + size_t refs; +} fd_table_t; + +/* XXX */ +#define SIG_COUNT 10 + +/* Signal Table */ +typedef struct signal_table { + uintptr_t functions[NUMSIGNALS+1]; +} sig_table_t; + +/* Portable process struct */ +typedef struct process { + pid_t id; /* Process ID (pid) */ + char * name; /* Process Name */ + char * description; /* Process description */ + user_t user; /* Effective user */ + int mask; /* Umask */ + + char ** cmdline; + + pid_t group; /* Process thread group */ + pid_t job; /* Process job group */ + pid_t session; /* Session group */ + + thread_t thread; /* Associated task information */ + tree_node_t * tree_entry; /* Process Tree Entry */ + image_t image; /* Binary image information */ + fs_node_t * wd_node; /* Working directory VFS node */ + char * wd_name; /* Working directory path name */ + fd_table_t * fds; /* File descriptor table */ + status_t status; /* Process status */ + sig_table_t signals; /* Signal table */ + uint8_t finished; /* Status indicator */ + uint8_t started; + uint8_t running; + struct regs * syscall_registers; /* Registers at interrupt */ + list_t * wait_queue; + list_t * shm_mappings; /* Shared memory chunk mappings */ + list_t * signal_queue; /* Queued signals */ + thread_t signal_state; + char * signal_kstack; + node_t sched_node; + node_t sleep_node; + node_t * timed_sleep_node; + uint8_t is_tasklet; + volatile uint8_t sleep_interrupted; + list_t * node_waits; + int awoken_index; + node_t * timeout_node; + struct timeval start; +} process_t; + +typedef struct { + unsigned long end_tick; + unsigned long end_subtick; + process_t * process; + int is_fswait; +} sleeper_t; + +extern void initialize_process_tree(void); +extern process_t * spawn_process(volatile process_t * parent, int reuse_fds); +extern void debug_print_process_tree(void); +extern process_t * spawn_init(void); +extern process_t * spawn_kidle(void); +extern void set_process_environment(process_t * proc, page_directory_t * directory); +extern void make_process_ready(process_t * proc); +extern uint8_t process_available(void); +extern process_t * next_ready_process(void); +extern uint32_t process_append_fd(process_t * proc, fs_node_t * node); +extern process_t * process_from_pid(pid_t pid); +extern void delete_process(process_t * proc); +process_t * process_get_parent(process_t * process); +extern uint32_t process_move_fd(process_t * proc, int src, int dest); +extern int process_is_ready(process_t * proc); + +extern void wakeup_sleepers(unsigned long seconds, unsigned long subseconds); +extern void sleep_until(process_t * process, unsigned long seconds, unsigned long subseconds); + +extern volatile process_t * current_process; +extern process_t * kernel_idle_task; +extern list_t * process_list; + +extern int process_wait_nodes(process_t * process,fs_node_t * nodes[], int timeout); +extern int process_alert_node(process_t * process, void * value); +extern int process_awaken_from_fswait(process_t * process, int index); + +typedef void (*tasklet_t) (void *, char *); +extern int create_kernel_tasklet(tasklet_t tasklet, char * name, void * argp); + +extern void release_directory(page_directory_t * dir); +extern void release_directory_for_exec(page_directory_t * dir); + +extern void cleanup_process(process_t * proc, int retval); +extern void reap_process(process_t * proc); +extern int waitpid(int pid, int * status, int options); + +extern int is_valid_process(process_t * process); + diff --git a/kernel/include/ringbuffer.h b/kernel/include/ringbuffer.h new file mode 100644 index 00000000..80bcae68 --- /dev/null +++ b/kernel/include/ringbuffer.h @@ -0,0 +1,26 @@ +#pragma once + +typedef struct { + unsigned char * buffer; + size_t write_ptr; + size_t read_ptr; + size_t size; + volatile int lock[2]; + list_t * wait_queue_readers; + list_t * wait_queue_writers; + int internal_stop; + list_t * alert_waiters; + int discard; +} ring_buffer_t; + +size_t ring_buffer_unread(ring_buffer_t * ring_buffer); +size_t ring_buffer_size(fs_node_t * node); +size_t ring_buffer_available(ring_buffer_t * ring_buffer); +size_t ring_buffer_read(ring_buffer_t * ring_buffer, size_t size, uint8_t * buffer); +size_t ring_buffer_write(ring_buffer_t * ring_buffer, size_t size, uint8_t * buffer); + +ring_buffer_t * ring_buffer_create(size_t size); +void ring_buffer_destroy(ring_buffer_t * ring_buffer); +void ring_buffer_interrupt(ring_buffer_t * ring_buffer); +void ring_buffer_select_wait(ring_buffer_t * ring_buffer, void * process); + diff --git a/kernel/include/shm.h b/kernel/include/shm.h new file mode 100644 index 00000000..46a36f7f --- /dev/null +++ b/kernel/include/shm.h @@ -0,0 +1,42 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once + +#include +#include + +#define SHM_PATH_SEPARATOR "." + +/* Types */ +struct shm_node; + +typedef struct { + struct shm_node * parent; + volatile uint8_t lock; + int32_t ref_count; + + uint32_t num_frames; + uintptr_t *frames; +} shm_chunk_t; + +typedef struct shm_node { + char name[256]; + shm_chunk_t * chunk; +} shm_node_t; + +typedef struct { + shm_chunk_t * chunk; + uint8_t volatile lock; + + uint32_t num_vaddrs; + uintptr_t *vaddrs; +} shm_mapping_t; + +/* Syscalls */ +extern void * shm_obtain(char * path, size_t * size); +extern int shm_release(char * path); + +/* Other exposed functions */ +extern void shm_install(void); +extern void shm_release_all(process_t * proc); + diff --git a/kernel/include/signal.h b/kernel/include/signal.h new file mode 100644 index 00000000..fdd43cce --- /dev/null +++ b/kernel/include/signal.h @@ -0,0 +1,11 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ + +#pragma once + +#include +void return_from_signal_handler(void); +void fix_signal_stacks(void); + +#include + diff --git a/kernel/include/signal_defs.h b/kernel/include/signal_defs.h new file mode 120000 index 00000000..c8d6f97b --- /dev/null +++ b/kernel/include/signal_defs.h @@ -0,0 +1 @@ +../../include/sys/signal_defs.h \ No newline at end of file diff --git a/kernel/include/syscall_nums.h b/kernel/include/syscall_nums.h new file mode 120000 index 00000000..7a58c47d --- /dev/null +++ b/kernel/include/syscall_nums.h @@ -0,0 +1 @@ +../../include/syscall_nums.h \ No newline at end of file diff --git a/kernel/include/system.h b/kernel/include/system.h new file mode 100644 index 00000000..08ab5941 --- /dev/null +++ b/kernel/include/system.h @@ -0,0 +1,234 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#define ASSUME(cond) __extension__ ({ if (!(cond)) { __builtin_unreachable(); } }) + +#define STR(x) #x +#define STRSTR(x) STR(x) + +#define asm __asm__ +#define volatile __volatile__ + +void int_disable(void); +void int_resume(void); +void int_enable(void); + +#define IRQ_OFF int_disable() +#define IRQ_RES int_resume() +#define IRQ_ON int_enable() +#define PAUSE { asm volatile ("hlt"); } + +#define STOP while (1) { PAUSE; } + +#define SYSCALL_VECTOR 0x7F +#define SIGNAL_RETURN 0xFFFFDEAF +#define THREAD_RETURN 0xFFFFB00F + +extern void * code; +extern void * end; + +extern char * boot_arg; /* Argument to pass to init */ +extern char * boot_arg_extra; /* Extra data to pass to init */ + +extern void *sbrk(uintptr_t increment); + +/* spin.c */ +typedef volatile int spin_lock_t[2]; +extern void spin_init(spin_lock_t lock); +extern void spin_lock(spin_lock_t lock); +extern void spin_unlock(spin_lock_t lock); + +extern void return_to_userspace(void); + +/* Kernel Main */ +extern unsigned short *memsetw(unsigned short *dest, unsigned short val, int count); + +extern unsigned char inportb(unsigned short _port); +extern void outportb(unsigned short _port, unsigned char _data); +extern unsigned short inports(unsigned short _port); +extern void outports(unsigned short _port, unsigned short _data); +extern unsigned int inportl(unsigned short _port); +extern void outportl(unsigned short _port, unsigned int _data); +extern void outportsm(unsigned short port, unsigned char * data, unsigned long size); +extern void inportsm(unsigned short port, unsigned char * data, unsigned long size); + + +extern size_t lfind(const char * str, const char accept); +extern size_t rfind(const char * str, const char accept); + +extern uint32_t krand(void); + +extern uint8_t startswith(const char * str, const char * accept); + +/* GDT */ +extern void gdt_install(void); +extern void gdt_set_gate(uint8_t num, uint64_t base, uint64_t limit, uint8_t access, uint8_t gran); +extern void set_kernel_stack(uintptr_t stack); + +/* IDT */ +extern void idt_install(void); +extern void idt_set_gate(uint8_t num, void (*base)(void), uint16_t sel, uint8_t flags); + +/* Registers + * + * Note: if the order of these changes, sys/task.S must be changed to use + * the correct offsets as well. + */ +struct regs { + unsigned int gs, fs, es, ds; + unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; + unsigned int int_no, err_code; + unsigned int eip, cs, eflags, useresp, ss; +}; + +typedef struct regs regs_t; + +typedef void (*irq_handler_t) (struct regs *); +typedef int (*irq_handler_chain_t) (struct regs *); + +/* Panic */ +#define HALT_AND_CATCH_FIRE(mesg, regs) halt_and_catch_fire(mesg, __FILE__, __LINE__, regs) +#define assert(statement) ((statement) ? (void)0 : assert_failed(__FILE__, __LINE__, #statement)) +void halt_and_catch_fire(char *error_message, const char *file, int line, struct regs * regs); +void assert_failed(const char *file, uint32_t line, const char *desc); + +/* ISRS */ +extern void isrs_install(void); +extern void isrs_install_handler(size_t isrs, irq_handler_t); +extern void isrs_uninstall_handler(size_t isrs); + +/* Interrupt Handlers */ +extern void irq_install(void); +extern void irq_install_handler(size_t irq, irq_handler_chain_t); +extern void irq_uninstall_handler(size_t irq); +extern int irq_is_handler_free(size_t irq); +extern void irq_gates(void); +extern void irq_ack(size_t); + +/* Timer */ +extern void timer_install(void); +extern unsigned long timer_ticks; +extern unsigned long timer_subticks; +extern signed long timer_drift; +extern void relative_time(unsigned long seconds, unsigned long subseconds, unsigned long * out_seconds, unsigned long * out_subseconds); + +/* Memory Management */ +extern uintptr_t placement_pointer; +extern void kmalloc_startat(uintptr_t address); +extern uintptr_t kmalloc_real(size_t size, int align, uintptr_t * phys); +extern uintptr_t kmalloc(size_t size); +extern uintptr_t kvmalloc(size_t size); +extern uintptr_t kmalloc_p(size_t size, uintptr_t * phys); +extern uintptr_t kvmalloc_p(size_t size, uintptr_t * phys); + +// Page types moved to task.h + +extern page_directory_t *kernel_directory; +extern page_directory_t *current_directory; + +extern void paging_install(uint32_t memsize); +extern void paging_prestart(void); +extern void paging_finalize(void); +extern void paging_mark_system(uint64_t addr); +extern void switch_page_directory(page_directory_t * new); +extern void invalidate_page_tables(void); +extern void invalidate_tables_at(uintptr_t addr); +extern page_t *get_page(uintptr_t address, int make, page_directory_t * dir); +extern void page_fault(struct regs *r); +extern void dma_frame(page_t * page, int, int, uintptr_t); +extern void debug_print_directory(page_directory_t *); + +int debug_shell_start(void); + +void heap_install(void); + +void alloc_frame(page_t *page, int is_kernel, int is_writeable); +void free_frame(page_t *page); +uintptr_t memory_use(void); +uintptr_t memory_total(void); + +/* klmalloc */ +void * __attribute__ ((malloc)) malloc(size_t size); +void * __attribute__ ((malloc)) realloc(void *ptr, size_t size); +void * __attribute__ ((malloc)) calloc(size_t nmemb, size_t size); +void * __attribute__ ((malloc)) valloc(size_t size); +void free(void *ptr); + +/* Tasks */ +extern uintptr_t read_eip(void); +extern void copy_page_physical(uint32_t, uint32_t); +extern page_directory_t * clone_directory(page_directory_t * src); +extern page_table_t * clone_table(page_table_t * src, uintptr_t * physAddr); +extern void move_stack(void *new_stack_start, size_t size); +extern void kexit(int retval); +extern void task_exit(int retval); +extern uint32_t next_pid; + +extern void tasking_install(void); +extern void switch_task(uint8_t reschedule); +extern void switch_next(void); +extern uint32_t fork(void); +extern uint32_t clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg); +extern uint32_t getpid(void); +extern void enter_user_jmp(uintptr_t location, int argc, char ** argv, uintptr_t stack); + +extern uintptr_t initial_esp; + +/* Kernel Argument Parser */ +extern void parse_args(char * argv); + +/* CMOS */ +extern void get_time(uint16_t * hours, uint16_t * minutes, uint16_t * seconds); +extern void get_date(uint16_t * month, uint16_t * day); +extern uint32_t boot_time; +extern uint32_t read_cmos(void); + +extern int gettimeofday(struct timeval * t, void * z); +extern uint32_t now(void); + + +/* Floating Point Unit */ +extern void switch_fpu(void); +extern void unswitch_fpu(void); +extern void fpu_install(void); + +/* ELF */ +extern int exec( char *, int, char **, char **); +extern int system( char *, int, char **); + +/* Sytem Calls */ +extern void syscalls_install(void); + +/* wakeup queue */ +extern int wakeup_queue(list_t * queue); +extern int wakeup_queue_interrupted(list_t * queue); +extern int sleep_on(list_t * queue); + +typedef struct { + uint32_t signum; + uintptr_t handler; + regs_t registers_before; +} signal_t; + +extern void handle_signal(process_t *, signal_t *); + +extern int send_signal(pid_t process, uint32_t signal); + +#define USER_STACK_BOTTOM 0xAFF00000 +#define USER_STACK_TOP 0xB0000000 +#define SHM_START 0xB0000000 + +extern void validate(void * ptr); +extern int validate_safe(void * ptr); + +#include + diff --git a/kernel/include/task.h b/kernel/include/task.h new file mode 100644 index 00000000..1498a329 --- /dev/null +++ b/kernel/include/task.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +typedef struct page { + unsigned int present:1; + unsigned int rw:1; + unsigned int user:1; + unsigned int writethrough:1; + unsigned int cachedisable:1; + unsigned int unused:7; + unsigned int frame:20; +} __attribute__((packed)) page_t; + +typedef struct page_table { + page_t pages[1024]; +} page_table_t; + +typedef struct page_directory { + uintptr_t physical_tables[1024]; /* Physical addresses of the tables */ + page_table_t *tables[1024]; /* 1024 pointers to page tables... */ + uintptr_t physical_address; /* The physical address of physical_tables */ + int32_t ref_count; +} page_directory_t; + diff --git a/kernel/include/termemu.h b/kernel/include/termemu.h new file mode 120000 index 00000000..53fc1eea --- /dev/null +++ b/kernel/include/termemu.h @@ -0,0 +1 @@ +../../lib/termemu.h \ No newline at end of file diff --git a/kernel/include/termios.h b/kernel/include/termios.h new file mode 120000 index 00000000..7c1e56d7 --- /dev/null +++ b/kernel/include/termios.h @@ -0,0 +1 @@ +../../include/sys/termios.h \ No newline at end of file diff --git a/kernel/include/tokenize.h b/kernel/include/tokenize.h new file mode 100644 index 00000000..a9d3ba0c --- /dev/null +++ b/kernel/include/tokenize.h @@ -0,0 +1,4 @@ +#pragma once + +int tokenize(char *, char *, char **); + diff --git a/kernel/include/tree.h b/kernel/include/tree.h new file mode 100644 index 00000000..0fa774d8 --- /dev/null +++ b/kernel/include/tree.h @@ -0,0 +1,37 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * General-purpose tree implementation + */ +#pragma once + +#include "list.h" + +typedef struct tree_node { + void * value; + list_t * children; + struct tree_node * parent; +} tree_node_t; + +typedef struct { + size_t nodes; + tree_node_t * root; +} tree_t; + +typedef uint8_t (*tree_comparator_t) (void *, void *); + +tree_t * tree_create(void); +void tree_set_root(tree_t * tree, void * value); +void tree_node_destroy(tree_node_t * node); +void tree_destroy(tree_t * tree); +void tree_free(tree_t * tree); +tree_node_t * tree_node_create(void * value); +void tree_node_insert_child_node(tree_t * tree, tree_node_t * parent, tree_node_t * node); +tree_node_t * tree_node_insert_child(tree_t * tree, tree_node_t * parent, void * value); +tree_node_t * tree_node_find_parent(tree_node_t * haystack, tree_node_t * needle); +void tree_node_parent_remove(tree_t * tree, tree_node_t * parent, tree_node_t * node); +void tree_node_remove(tree_t * tree, tree_node_t * node); +void tree_remove(tree_t * tree, tree_node_t * node); +tree_node_t * tree_find(tree_t * tree, void * value, tree_comparator_t comparator); +void tree_break_off(tree_t * tree, tree_node_t * node); + + diff --git a/kernel/include/tss.h b/kernel/include/tss.h new file mode 100644 index 00000000..4fe22565 --- /dev/null +++ b/kernel/include/tss.h @@ -0,0 +1,37 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once + +extern void tss_flush(void); + +typedef struct tss_entry { + uint32_t prev_tss; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldt; + uint16_t trap; + uint16_t iomap_base; +} __attribute__ ((packed)) tss_entry_t; + + diff --git a/kernel/include/types.h b/kernel/include/types.h new file mode 100644 index 00000000..9f6a2991 --- /dev/null +++ b/kernel/include/types.h @@ -0,0 +1,18 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + */ +#pragma once + +/* Types */ + +#define NULL ((void *)0UL) + +#include + +typedef unsigned long size_t; +#define CHAR_BIT 8 + +struct timeval { + uint32_t tv_sec; + uint32_t tv_usec; +}; + diff --git a/kernel/include/ubsan.h b/kernel/include/ubsan.h new file mode 100644 index 00000000..86d0014e --- /dev/null +++ b/kernel/include/ubsan.h @@ -0,0 +1,68 @@ +#pragma once + +#include + +struct TypeDescriptor { + uint16_t type_kind; + uint16_t type_info; + char type_name[1]; +}; + +struct SourceLocation { + const char *file_name; + uint32_t line; + uint32_t column; +}; + +struct OverflowData { + struct SourceLocation location; + struct TypeDescriptor *type; +}; + +struct TypeMismatchData { + struct SourceLocation location; + struct TypeDescriptor *type; + unsigned long alignment; + unsigned char type_check_kind; +}; + +struct NonnullArgData { + struct SourceLocation location; + struct SourceLocation attr_location; + int arg_index; +}; + +struct NonnullReturnData { + struct SourceLocation location; + struct SourceLocation attr_location; +}; + +struct VLABoundData { + struct SourceLocation location; + struct TypeDescriptor *type; +}; + +struct OutOfBoundsData { + struct SourceLocation location; + struct TypeDescriptor *array_type; + struct TypeDescriptor *index_type; +}; + +struct ShiftOutOfBoundsData { + struct SourceLocation location; + struct TypeDescriptor *lhs_type; + struct TypeDescriptor *rhs_type; +}; + +struct UnreachableData { + struct SourceLocation location; +}; + +struct InvalidValueData { + struct SourceLocation location; + struct TypeDescriptor *type; +}; + +typedef int64_t s_max; +typedef uint64_t u_max; + diff --git a/kernel/include/utsname.h b/kernel/include/utsname.h new file mode 120000 index 00000000..1da0f9fb --- /dev/null +++ b/kernel/include/utsname.h @@ -0,0 +1 @@ +../../include/sys/utsname.h \ No newline at end of file diff --git a/kernel/include/va_list.h b/kernel/include/va_list.h new file mode 100644 index 00000000..cbabf306 --- /dev/null +++ b/kernel/include/va_list.h @@ -0,0 +1,8 @@ +#pragma once + +typedef __builtin_va_list va_list; +#define va_start(ap,last) __builtin_va_start(ap, last) +#define va_end(ap) __builtin_va_end(ap) +#define va_arg(ap,type) __builtin_va_arg(ap,type) +#define va_copy(dest, src) __builtin_va_copy(dest,src) + diff --git a/kernel/include/version.h b/kernel/include/version.h new file mode 100644 index 00000000..a19664be --- /dev/null +++ b/kernel/include/version.h @@ -0,0 +1,19 @@ +#pragma once + +extern char * __kernel_name; +extern char * __kernel_version_format; + +extern int __kernel_version_major; +extern int __kernel_version_minor; +extern int __kernel_version_lower; + +extern char * __kernel_version_suffix; +extern char * __kernel_version_codename; + +extern char * __kernel_arch; + +extern char * __kernel_build_date; +extern char * __kernel_build_time; + +extern char * __kernel_compiler_version; + diff --git a/kernel/include/video.h b/kernel/include/video.h new file mode 100644 index 00000000..3244e54c --- /dev/null +++ b/kernel/include/video.h @@ -0,0 +1,18 @@ +#pragma once + +#define IO_VID_WIDTH 0x5001 +#define IO_VID_HEIGHT 0x5002 +#define IO_VID_DEPTH 0x5003 +#define IO_VID_ADDR 0x5004 +#define IO_VID_SIGNAL 0x5005 +#define IO_VID_SET 0x5006 +#define IO_VID_STRIDE 0x5007 + +#ifdef _KERNEL_ +extern void lfb_set_resolution(uint16_t x, uint16_t y); +extern uint16_t lfb_resolution_x; +extern uint16_t lfb_resolution_y; +extern uint16_t lfb_resolution_b; +extern uint8_t * lfb_vid_memory; +#endif + diff --git a/kernel/irq.S b/kernel/irq.S new file mode 100644 index 00000000..56b706fa --- /dev/null +++ b/kernel/irq.S @@ -0,0 +1,67 @@ +.section .text +.align 4 + +.macro IRQ ident byte + .global _irq\ident + .type _irq\ident, @function + _irq\ident: + cli + push $0x00 + push $\byte + jmp irq_common +.endm + +/* Interrupt Requests */ +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 + +.extern irq_handler +.type irq_handler, @function + +irq_common: + /* Save all registers */ + pusha + + /* Save segment registers */ + push %ds + push %es + push %fs + push %gs + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + cld + + /* Call interrupt handler */ + push %esp + call irq_handler + add $4, %esp + + /* Restore segment registers */ + pop %gs + pop %fs + pop %es + pop %ds + + /* Restore all registers */ + popa + /* Cleanup error code and IRQ # */ + add $8, %esp + /* pop CS, EIP, EFLAGS, SS and ESP */ + iret diff --git a/kernel/isr.S b/kernel/isr.S new file mode 100644 index 00000000..318c0498 --- /dev/null +++ b/kernel/isr.S @@ -0,0 +1,91 @@ +.section .text +.align 4 + +.macro ISR_NOERR index + .global _isr\index + _isr\index: + cli + push $0 + push $\index + jmp isr_common +.endm + +.macro ISR_ERR index + .global _isr\index + _isr\index: + cli + push $\index + jmp isr_common +.endm + +/* Standard X86 interrupt service routines */ +ISR_NOERR 0 +ISR_NOERR 1 +ISR_NOERR 2 +ISR_NOERR 3 +ISR_NOERR 4 +ISR_NOERR 5 +ISR_NOERR 6 +ISR_NOERR 7 +ISR_ERR 8 +ISR_NOERR 9 +ISR_ERR 10 +ISR_ERR 11 +ISR_ERR 12 +ISR_ERR 13 +ISR_ERR 14 +ISR_NOERR 15 +ISR_NOERR 16 +ISR_NOERR 17 +ISR_NOERR 18 +ISR_NOERR 19 +ISR_NOERR 20 +ISR_NOERR 21 +ISR_NOERR 22 +ISR_NOERR 23 +ISR_NOERR 24 +ISR_NOERR 25 +ISR_NOERR 26 +ISR_NOERR 27 +ISR_NOERR 28 +ISR_NOERR 29 +ISR_NOERR 30 +ISR_NOERR 31 +ISR_NOERR 127 + +.extern fault_handler +.type fault_handler, @function + +isr_common: + /* Push all registers */ + pusha + + /* Save segment registers */ + push %ds + push %es + push %fs + push %gs + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + cld + + /* Call fault handler */ + push %esp + call fault_handler + add $4, %esp + + /* Restore segment registers */ + pop %gs + pop %fs + pop %es + pop %ds + + /* Restore registers */ + popa + /* Cleanup error code and ISR # */ + add $8, %esp + /* pop CS, EIP, EFLAGS, SS and ESP */ + iret diff --git a/kernel/libc.c b/kernel/libc.c new file mode 100644 index 00000000..e3779ca6 --- /dev/null +++ b/kernel/libc.c @@ -0,0 +1,454 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015 Dale Weiler + * + * Standard C library for kernel + * + */ + +#include +#include + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(X) (((X)-ONES) & ~(X) & HIGHS) + +#define BITOP(A, B, OP) \ + ((A)[(size_t)(B)/(8*sizeof *(A))] OP (size_t)1<<((size_t)(B)%(8*sizeof *(A)))) + +void * memcpy(void * restrict dest, const void * restrict src, size_t n) { + asm volatile("cld; rep movsb" + : "=c"((int){0}) + : "D"(dest), "S"(src), "c"(n) + : "flags", "memory"); + return dest; +} + +void * memset(void * dest, int c, size_t n) { + asm volatile("cld; rep stosb" + : "=c"((int){0}) + : "D"(dest), "a"(c), "c"(n) + : "flags", "memory"); + return dest; +} + +int memcmp(const void * vl, const void * vr, size_t n) { + const unsigned char *l = vl; + const unsigned char *r = vr; + for (; n && *l == *r; n--, l++, r++); + return n ? *l-*r : 0; +} + +void * memchr(const void * src, int c, size_t n) { + const unsigned char * s = src; + c = (unsigned char)c; + for (; ((uintptr_t)s & (ALIGN - 1)) && n && *s != c; s++, n--); + if (n && *s != c) { + const size_t * w; + size_t k = ONES * c; + for (w = (const void *)s; n >= sizeof(size_t) && !HASZERO(*w^k); w++, n -= sizeof(size_t)); + for (s = (const void *)w; n && *s != c; s++, n--); + } + return n ? (void *)s : 0; +} + +void * memrchr(const void * m, int c, size_t n) { + const unsigned char * s = m; + c = (unsigned char)c; + while (n--) { + if (s[n] == c) { + return (void*)(s+n); + } + } + return 0; +} + +void * memmove(void * dest, const void * src, size_t n) { + char * d = dest; + const char * s = src; + + if (d==s) { + return d; + } + + if (s+n <= d || d+n <= s) { + return memcpy(d, s, n); + } + + if (d= sizeof(size_t); n -= sizeof(size_t), d += sizeof(size_t), s += sizeof(size_t)) { + *(size_t *)d = *(size_t *)s; + } + } + for (; n; n--) { + *d++ = *s++; + } + } else { + if ((uintptr_t)s % sizeof(size_t) == (uintptr_t)d % sizeof(size_t)) { + while ((uintptr_t)(d+n) % sizeof(size_t)) { + if (!n--) { + return dest; + } + d[n] = s[n]; + } + while (n >= sizeof(size_t)) { + n -= sizeof(size_t); + *(size_t *)(d+n) = *(size_t *)(s+n); + } + } + while (n) { + n--; + d[n] = s[n]; + } + } + + return dest; +} + +int strcmp(const char * l, const char * r) { + for (; *l == *r && *l; l++, r++); + return *(unsigned char *)l - *(unsigned char *)r; +} + +size_t strlen(const char * s) { + const char * a = s; + const size_t * w; + for (; (uintptr_t)s % ALIGN; s++) { + if (!*s) { + return s-a; + } + } + for (w = (const void *)s; !HASZERO(*w); w++); + for (s = (const void *)w; *s; s++); + return s-a; +} + +char * strdup(const char * s) { + size_t l = strlen(s); + return memcpy(malloc(l+1), s, l+1); +} + +char * stpcpy(char * restrict d, const char * restrict s) { + size_t * wd; + const size_t * ws; + + if ((uintptr_t)s % ALIGN == (uintptr_t)d % ALIGN) { + for (; (uintptr_t)s % ALIGN; s++, d++) { + if (!(*d = *s)) { + return d; + } + } + wd = (void *)d; + ws = (const void *)s; + for (; !HASZERO(*ws); *wd++ = *ws++); + d = (void *)wd; + s = (const void *)ws; + } + + for (; (*d=*s); s++, d++); + + return d; +} + +char * strcpy(char * restrict dest, const char * restrict src) { + stpcpy(dest, src); + return dest; +} + +size_t strspn(const char * s, const char * c) { + const char * a = s; + size_t byteset[32/sizeof(size_t)] = { 0 }; + + if (!c[0]) { + return 0; + } + if (!c[1]) { + for (; *s == *c; s++); + return s-a; + } + + for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++); + for (; *s && BITOP(byteset, *(unsigned char *)s, &); s++); + + return s-a; +} + +char * strchrnul(const char * s, int c) { + size_t * w; + size_t k; + + c = (unsigned char)c; + if (!c) { + return (char *)s + strlen(s); + } + + for (; (uintptr_t)s % ALIGN; s++) { + if (!*s || *(unsigned char *)s == c) { + return (char *)s; + } + } + + k = ONES * c; + for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++); + for (s = (void *)w; *s && *(unsigned char *)s != c; s++); + return (char *)s; +} + +char * strchr(const char * s, int c) { + char *r = strchrnul(s, c); + return *(unsigned char *)r == (unsigned char)c ? r : 0; +} + +char * strrchr(const char * s, int c) { + return memrchr(s, c, strlen(s) + 1); +} + +size_t strcspn(const char * s, const char * c) { + const char *a = s; + if (c[0] && c[1]) { + size_t byteset[32/sizeof(size_t)] = { 0 }; + for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++); + for (; *s && !BITOP(byteset, *(unsigned char *)s, &); s++); + return s-a; + } + return strchrnul(s, *c)-a; +} + +char * strpbrk(const char * s, const char * b) { + s += strcspn(s, b); + return *s ? (char *)s : 0; +} + +static char *strstr_2b(const unsigned char * h, const unsigned char * n) { + uint16_t nw = n[0] << 8 | n[1]; + uint16_t hw = h[0] << 8 | h[1]; + for (h++; *h && hw != nw; hw = hw << 8 | *++h); + return *h ? (char *)h-1 : 0; +} + +static char *strstr_3b(const unsigned char * h, const unsigned char * n) { + uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8; + uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8; + for (h += 2; *h && hw != nw; hw = (hw|*++h) << 8); + return *h ? (char *)h-2 : 0; +} + +static char *strstr_4b(const unsigned char * h, const unsigned char * n) { + uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; + uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; + for (h += 3; *h && hw != nw; hw = hw << 8 | *++h); + return *h ? (char *)h-3 : 0; +} + +static char *strstr_twoway(const unsigned char * h, const unsigned char * n) { + size_t mem; + size_t mem0; + size_t byteset[32 / sizeof(size_t)] = { 0 }; + size_t shift[256]; + size_t l; + + /* Computing length of needle and fill shift table */ + for (l = 0; n[l] && h[l]; l++) { + BITOP(byteset, n[l], |=); + shift[n[l]] = l+1; + } + + if (n[l]) { + return 0; /* hit the end of h */ + } + + /* Compute maximal suffix */ + size_t ip = -1; + size_t jp = 0; + size_t k = 1; + size_t p = 1; + while (jp+k n[jp+k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + size_t ms = ip; + size_t p0 = p; + + /* And with the opposite comparison */ + ip = -1; + jp = 0; + k = p = 1; + while (jp+k ms+1) { + ms = ip; + } else { + p = p0; + } + + /* Periodic needle? */ + if (memcmp(n, n+p, ms+1)) { + mem0 = 0; + p = MAX(ms, l-ms-1) + 1; + } else { + mem0 = l-p; + } + mem = 0; + + /* Initialize incremental end-of-haystack pointer */ + const unsigned char * z = h; + + /* Search loop */ + for (;;) { + /* Update incremental end-of-haystack pointer */ + if ((size_t)(z-h) < l) { + /* Fast estimate for MIN(l,63) */ + size_t grow = l | 63; + const unsigned char *z2 = memchr(z, 0, grow); + if (z2) { + z = z2; + if ((size_t)(z-h) < l) { + return 0; + } + } else { + z += grow; + } + } + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l-1], &)) { + k = l-shift[h[l-1]]; + if (k) { + if (mem0 && mem && k < p) k = l-p; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++); + if (n[k]) { + h += k-ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--); + if (k <= mem) { + return (char *)h; + } + h += p; + mem = mem0; + } +} + +char *strstr(const char * h, const char * n) { + /* Return immediately on empty needle */ + if (!n[0]) { + return (char *)h; + } + + /* Use faster algorithms for short needles */ + h = strchr(h, *n); + if (!h || !n[1]) { + return (char *)h; + } + + if (!h[1]) return 0; + if (!n[2]) return strstr_2b((void *)h, (void *)n); + if (!h[2]) return 0; + if (!n[3]) return strstr_3b((void *)h, (void *)n); + if (!h[3]) return 0; + if (!n[4]) return strstr_4b((void *)h, (void *)n); + + /* Two-way on large needles */ + return strstr_twoway((void *)h, (void *)n); +} + +static inline int isdigit(int ch) { + return (unsigned int)ch-'0' < 10; +} + +static inline int isspace(int ch) { + return ch == ' ' || (unsigned int)ch-'\t' < 5; +} + +int atoi(const char * s) { + int n = 0; + int neg = 0; + while (isspace(*s)) { + s++; + } + switch (*s) { + case '-': + neg = 1; + /* Fallthrough is intentional here */ + case '+': + s++; + } + while (isdigit(*s)) { + n = 10*n - (*s++ - '0'); + } + /* The sign order may look incorrect here but this is correct as n is calculated + * as a negative number to avoid overflow on INT_MAX. + */ + return neg ? n : -n; +} + +char * strtok_r(char * str, const char * delim, char ** saveptr) { + char * token; + if (str == NULL) { + str = *saveptr; + } + str += strspn(str, delim); + if (*str == '\0') { + *saveptr = str; + return NULL; + } + token = str; + str = strpbrk(token, delim); + if (str == NULL) { + *saveptr = (char *)lfind(token, '\0'); + } else { + *str = '\0'; + *saveptr = str + 1; + } + return token; +} diff --git a/kernel/link.ld b/kernel/link.ld new file mode 100644 index 00000000..f3a72fc1 --- /dev/null +++ b/kernel/link.ld @@ -0,0 +1,49 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * Kernel linker script for x86 + */ +OUTPUT_FORMAT(elf32-i386) +ENTRY(start) + +SECTIONS +{ + . = 1M; + phys = .; + + .text BLOCK(4K) : ALIGN(4K) + { + code = .; + *(.multiboot) + *(.text) + } + + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + .data BLOCK(4K) : ALIGN(4K) + { + data = .; + *(.data) + *(.symbols) + PROVIDE(kernel_symbols_start = .); + PROVIDE(kernel_symbols_end = .); + } + + .bss BLOCK(4K) : ALIGN(4K) + { + bss = .; + *(COMMON) + *(.bss) + *(.stack) + } + + end = .; + + /DISCARD/ : + { + *(.comment) + *(.eh_frame) + *(.note.gnu.build-id) + } +} diff --git a/kernel/main.c b/kernel/main.c new file mode 100644 index 00000000..37a478e4 --- /dev/null +++ b/kernel/main.c @@ -0,0 +1,255 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * The ToAruOS kernel is released under the terms of the + * University of Illinois / NCSA License. + * + * Copyright (C) 2011-2014 Kevin Lange. All rights reserved. + * Copyright (C) 2012 Markus Schober + * Copyright (C) 2014 Lioncash + * + * Dedicated to the memory of + * Dennis Ritchie + * 1941-2011 + * + * Developed by: ToAruOS Kernel Development Team + * http://github.com/klange/osdev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal with the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimers. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimers in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the ToAruOS Kernel Development Team, Kevin Lange, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without specific prior + * written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * WITH THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +uintptr_t initial_esp = 0; + +fs_node_t * ramdisk_mount(uintptr_t, size_t); + +#ifdef EARLY_BOOT_LOG +#define EARLY_LOG_DEVICE 0x3F8 +static uint32_t _early_log_write(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + for (unsigned int i = 0; i < size; ++i) { + outportb(EARLY_LOG_DEVICE, buffer[i]); + } + return size; +} +fs_node_t _early_log = { .write = &_early_log_write }; +#define ENABLE_EARLY_BOOT_LOG(level) do { debug_file = &_early_log; debug_level = (level); } while (0) +#define DISABLE_EARLY_BOOT_LOG() do { debug_file = NULL; debug_level = NOTICE; } while (0) +#else +#define ENABLE_EARLY_BOOT_LOG(level) +#define DISABLE_EARLY_BOOT_LOG() +#endif + +struct pack_header { + char head[4]; + uint32_t region_size; +}; + +/* + * multiboot i386 (pc) kernel entry point + */ +int kmain(struct multiboot *mboot, uint32_t mboot_mag, uintptr_t esp) { + initial_esp = esp; + extern char * cmdline; + + uint32_t mboot_mods_count = 0; + mboot_mod_t * mboot_mods = NULL; + mboot_ptr = mboot; + + ENABLE_EARLY_BOOT_LOG(0); + + assert(mboot_mag == MULTIBOOT_EAX_MAGIC && "Didn't boot with multiboot, not sure how we got here."); + debug_print(NOTICE, "Processing Multiboot information."); + + /* Initialize core modules */ + gdt_install(); /* Global descriptor table */ + idt_install(); /* IDT */ + isrs_install(); /* Interrupt service requests */ + irq_install(); /* Hardware interrupt requests */ + + if (mboot_ptr->flags & (1 << 3)) { + debug_print(NOTICE, "There %s %d module%s starting at 0x%x.", mboot_ptr->mods_count == 1 ? "is" : "are", mboot_ptr->mods_count, mboot_ptr->mods_count == 1 ? "" : "s", mboot_ptr->mods_addr); + debug_print(NOTICE, "Current kernel heap start point would be 0x%x.", &end); + if (mboot_ptr->mods_count > 0) { + uintptr_t last_mod = (uintptr_t)&end; + uint32_t i; + mboot_mods = (mboot_mod_t *)mboot_ptr->mods_addr; + mboot_mods_count = mboot_ptr->mods_count; + for (i = 0; i < mboot_ptr->mods_count; ++i ) { + mboot_mod_t * mod = &mboot_mods[i]; + uint32_t module_start = mod->mod_start; + uint32_t module_end = mod->mod_end; + if ((uintptr_t)mod + sizeof(mboot_mod_t) > last_mod) { + /* Just in case some silly person put this *behind* the modules... */ + last_mod = (uintptr_t)mod + sizeof(mboot_mod_t); + } + debug_print(NOTICE, "Module %d is at 0x%x:0x%x", i, module_start, module_end); + if (last_mod < module_end) { + last_mod = module_end; + } + } + debug_print(NOTICE, "Moving kernel heap start to 0x%x", last_mod); + kmalloc_startat(last_mod); + } + } + + paging_install(mboot_ptr->mem_upper + mboot_ptr->mem_lower); + if (mboot_ptr->flags & (1 << 6)) { + debug_print(NOTICE, "Parsing memory map."); + mboot_memmap_t * mmap = (void *)mboot_ptr->mmap_addr; + while ((uintptr_t)mmap < mboot_ptr->mmap_addr + mboot_ptr->mmap_length) { + if (mmap->type == 2) { + for (unsigned long long int i = 0; i < mmap->length; i += 0x1000) { + if (mmap->base_addr + i > 0xFFFFFFFF) break; /* xxx */ + debug_print(INFO, "Marking 0x%x", (uint32_t)(mmap->base_addr + i)); + paging_mark_system((mmap->base_addr + i) & 0xFFFFF000); + } + } + mmap = (mboot_memmap_t *) ((uintptr_t)mmap + mmap->size + sizeof(uintptr_t)); + } + } + paging_finalize(); + + { + char cmdline_[1024]; + + size_t len = strlen((char *)mboot_ptr->cmdline); + memmove(cmdline_, (char *)mboot_ptr->cmdline, len + 1); + + /* Relocate the command line */ + cmdline = (char *)kmalloc(len + 1); + memcpy(cmdline, cmdline_, len + 1); + } + + /* Memory management */ + heap_install(); /* Kernel heap */ + + if (cmdline) { + args_parse(cmdline); + } + + vfs_install(); + tasking_install(); /* Multi-tasking */ + timer_install(); /* PIC driver */ + fpu_install(); /* FPU/SSE magic */ + syscalls_install(); /* Install the system calls */ + shm_install(); /* Install shared memory */ + modules_install(); /* Modules! */ + + DISABLE_EARLY_BOOT_LOG(); + + /* Load modules from bootloader */ + debug_print(NOTICE, "%d modules to load", mboot_mods_count); + for (unsigned int i = 0; i < mboot_ptr->mods_count; ++i ) { + mboot_mod_t * mod = &mboot_mods[i]; + uint32_t module_start = mod->mod_start; + uint32_t module_end = mod->mod_end; + size_t module_size = module_end - module_start; + + int check_result = module_quickcheck((void *)module_start); + if (check_result == 1) { + debug_print(NOTICE, "Loading a module: 0x%x:0x%x", module_start, module_end); + module_data_t * mod_info = (module_data_t *)module_load_direct((void *)(module_start), module_size); + if (mod_info) { + debug_print(NOTICE, "Loaded: %s", mod_info->mod_info->name); + } + } else if (check_result == 2) { + /* Mod pack */ + debug_print(NOTICE, "Loading modpack. %x", module_start); + struct pack_header * pack_header = (struct pack_header *)module_start; + while (pack_header->region_size) { + void * start = (void *)((uintptr_t)pack_header + 4096); + int result = module_quickcheck(start); + if (result != 1) { + debug_print(WARNING, "Not actually a module?! %x", start); + } + module_data_t * mod_info = (module_data_t *)module_load_direct(start, pack_header->region_size); + if (mod_info) { + debug_print(NOTICE, "Loaded: %s", mod_info->mod_info->name); + } + pack_header = (struct pack_header *)((uintptr_t)start + pack_header->region_size); + } + debug_print(NOTICE, "Done with modpack."); + } else { + debug_print(NOTICE, "Loading ramdisk: 0x%x:0x%x", module_start, module_end); + ramdisk_mount(module_start, module_size); + } + } + + /* Map /dev to a device mapper */ + map_vfs_directory("/dev"); + + if (args_present("root")) { + char * root_type = "ext2"; + if (args_present("root_type")) { + root_type = args_value("root_type"); + } + vfs_mount_type(root_type, args_value("root"), "/"); + } + + if (args_present("start")) { + char * c = args_value("start"); + if (!c) { + debug_print(WARNING, "Expected an argument to kernel option `start`. Ignoring."); + } else { + debug_print(NOTICE, "Got start argument: %s", c); + boot_arg = strdup(c); + } + } + + if (!fs_root) { + map_vfs_directory("/"); + } + + char * boot_app = "/bin/init"; + if (args_present("init")) { + boot_app = args_value("init"); + } + + /* Prepare to run /bin/init */ + char * argv[] = { + boot_app, + boot_arg, + NULL + }; + int argc = 0; + while (argv[argc]) { + argc++; + } + system(argv[0], argc, argv); /* Run init */ + + debug_print(CRITICAL, "init failed"); + switch_task(0); + + return 0; +} + diff --git a/kernel/mem/alloc.c b/kernel/mem/alloc.c new file mode 100644 index 00000000..dc5ed4bc --- /dev/null +++ b/kernel/mem/alloc.c @@ -0,0 +1,969 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * + * Kevin Lange's Slab Allocator + * + * Implemented for CS241, Fall 2010, machine problem 7 + * at the University of Illinois, Urbana-Champaign. + * + * Overall competition winner for speed. + * Well ranked in memory usage. + * + * Copyright (c) 2010 Kevin Lange. All rights reserved. + * + * Developed by: Kevin Lange + * Dave Majnemer + * Assocation for Computing Machinery + * University of Illinois, Urbana-Champaign + * http://acm.uiuc.edu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal with the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimers. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimers in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the Association for Computing Machinery, the + * University of Illinois, nor the names of its contributors may be used + * to endorse or promote products derived from this Software without + * specific prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * WITH THE SOFTWARE. + * + * ########## + * # README # + * ########## + * + * About the slab allocator + * """""""""""""""""""""""" + * + * This is a simple implementation of a "slab" allocator. It works by operating + * on "bins" of items of predefined sizes and a set of pseudo-bins of any size. + * When a new allocation request is made, the allocator determines if it will + * fit in an existing bin. If there are no bins of the correct size for a given + * allocation request, the allocator will make a bin and add it to a(n empty) + * list of available bins of that size. In this implementation, we use sizes + * from 4 bytes (32 bit) or 8 bytes (64-bit) to 2KB for bins, fitting a 4K page + * size. The implementation allows the number of pages in a single bin to be + * increased, as well as allowing for changing the size of page (though this + * should, for the most part, remain 4KB under any modern system). + * + * Special thanks + * """""""""""""" + * + * I would like to thank Dave Majnemer, who I have credited above as a + * contributor, for his assistance. Without Dave, klmalloc would be a mash + * up of bits of forward movement in no discernible pattern. Dave helped + * me ensure that I could build a proper slab allocator and has consantly + * derided me for not fixing the bugs and to-do items listed in the last + * section of this readme. + * + * GCC Function Attributes + * """"""""""""""""""""""" + * + * A couple of GCC function attributes, designated by the __attribute__ + * directive, are used in this code to streamline optimization. + * I've chosen to include a brief overview of the particular attributes + * I am making use of: + * + * - malloc: + * Tells gcc that a given function is a memory allocator + * and that non-NULL values it returns should never be + * associated with other chunks of memory. We use this for + * alloc, realloc and calloc, as is requested in the gcc + * documentation for the attribute. + * + * - always_inline: + * Tells gcc to always inline the given code, regardless of the + * optmization level. Small functions that would be noticeably + * slower with the overhead of paramter handling are given + * this attribute. + * + * - pure: + * Tells gcc that a function only uses inputs and its output. + * + * Things to work on + * """"""""""""""""" + * + * TODO: Try to be more consistent on comment widths... + * FIXME: Make thread safe! Not necessary for competition, but would be nice. + * FIXME: Splitting/coalescing is broken. Fix this ASAP! + * +**/ + +/* Includes {{{ */ +#include +/* }}} */ +/* Definitions {{{ */ + +/* + * Defines for often-used integral values + * related to our binning and paging strategy. + */ +#define NUM_BINS 11U /* Number of bins, total, under 32-bit. */ +#define SMALLEST_BIN_LOG 2U /* Logarithm base two of the smallest bin: log_2(sizeof(int32)). */ +#define BIG_BIN (NUM_BINS - 1) /* Index for the big bin, (NUM_BINS - 1) */ +#define SMALLEST_BIN (1UL << SMALLEST_BIN_LOG) /* Size of the smallest bin. */ + +#define PAGE_SIZE 0x1000 /* Size of a page (in bytes), should be 4KB */ +#define PAGE_MASK (PAGE_SIZE - 1) /* Block mask, size of a page * number of pages - 1. */ +#define SKIP_P INT32_MAX /* INT32_MAX is half of UINT32_MAX; this gives us a 50% marker for skip lists. */ +#define SKIP_MAX_LEVEL 6 /* We have a maximum of 6 levels in our skip lists. */ + +#define BIN_MAGIC 0xDEFAD00D + +/* }}} */ + +/* + * Internal functions. + */ +static void * __attribute__ ((malloc)) klmalloc(uintptr_t size); +static void * __attribute__ ((malloc)) klrealloc(void * ptr, uintptr_t size); +static void * __attribute__ ((malloc)) klcalloc(uintptr_t nmemb, uintptr_t size); +static void * __attribute__ ((malloc)) klvalloc(uintptr_t size); +static void klfree(void * ptr); + +static spin_lock_t mem_lock = { 0 }; + +void * __attribute__ ((malloc)) malloc(uintptr_t size) { + spin_lock(mem_lock); + void * ret = klmalloc(size); + spin_unlock(mem_lock); + return ret; +} + +void * __attribute__ ((malloc)) realloc(void * ptr, uintptr_t size) { + spin_lock(mem_lock); + void * ret = klrealloc(ptr, size); + spin_unlock(mem_lock); + return ret; +} + +void * __attribute__ ((malloc)) calloc(uintptr_t nmemb, uintptr_t size) { + spin_lock(mem_lock); + void * ret = klcalloc(nmemb, size); + spin_unlock(mem_lock); + return ret; +} + +void * __attribute__ ((malloc)) valloc(uintptr_t size) { + spin_lock(mem_lock); + void * ret = klvalloc(size); + spin_unlock(mem_lock); + return ret; +} + +void free(void * ptr) { + spin_lock(mem_lock); + if ((uintptr_t)ptr > placement_pointer) { + klfree(ptr); + } + spin_unlock(mem_lock); +} + + +/* Bin management {{{ */ + +/* + * Adjust bin size in bin_size call to proper bounds. + */ +inline static uintptr_t __attribute__ ((always_inline, pure)) klmalloc_adjust_bin(uintptr_t bin) +{ + if (bin <= (uintptr_t)SMALLEST_BIN_LOG) + { + return 0; + } + bin -= SMALLEST_BIN_LOG + 1; + if (bin > (uintptr_t)BIG_BIN) { + return BIG_BIN; + } + return bin; +} + +/* + * Given a size value, find the correct bin + * to place the requested allocation in. + */ +inline static uintptr_t __attribute__ ((always_inline, pure)) klmalloc_bin_size(uintptr_t size) { + uintptr_t bin = sizeof(size) * CHAR_BIT - __builtin_clzl(size); + bin += !!(size & (size - 1)); + return klmalloc_adjust_bin(bin); +} + +/* + * Bin header - One page of memory. + * Appears at the front of a bin to point to the + * previous bin (or NULL if the first), the next bin + * (or NULL if the last) and the head of the bin, which + * is a stack of cells of data. + */ +typedef struct _klmalloc_bin_header { + struct _klmalloc_bin_header * next; /* Pointer to the next node. */ + void * head; /* Head of this bin. */ + uintptr_t size; /* Size of this bin, if big; otherwise bin index. */ + uint32_t bin_magic; +} klmalloc_bin_header; + +/* + * A big bin header is basically the same as a regular bin header + * only with a pointer to the previous (physically) instead of + * a "next" and with a list of forward headers. + */ +typedef struct _klmalloc_big_bin_header { + struct _klmalloc_big_bin_header * next; + void * head; + uintptr_t size; + uint32_t bin_magic; + struct _klmalloc_big_bin_header * prev; + struct _klmalloc_big_bin_header * forward[SKIP_MAX_LEVEL+1]; +} klmalloc_big_bin_header; + + +/* + * List of pages in a bin. + */ +typedef struct _klmalloc_bin_header_head { + klmalloc_bin_header * first; +} klmalloc_bin_header_head; + +/* + * Array of available bins. + */ +static klmalloc_bin_header_head klmalloc_bin_head[NUM_BINS - 1]; /* Small bins */ +static struct _klmalloc_big_bins { + klmalloc_big_bin_header head; + int level; +} klmalloc_big_bins; +static klmalloc_big_bin_header * klmalloc_newest_big = NULL; /* Newest big bin */ + +/* }}} Bin management */ +/* Doubly-Linked List {{{ */ + +/* + * Remove an entry from a page list. + * Decouples the element from its + * position in the list by linking + * its neighbors to eachother. + */ +inline static void __attribute__ ((always_inline)) klmalloc_list_decouple(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { + klmalloc_bin_header *next = node->next; + head->first = next; + node->next = NULL; +} + +/* + * Insert an entry into a page list. + * The new entry is placed at the front + * of the list and the existing border + * elements are updated to point back + * to it (our list is doubly linked). + */ +inline static void __attribute__ ((always_inline)) klmalloc_list_insert(klmalloc_bin_header_head *head, klmalloc_bin_header *node) { + node->next = head->first; + head->first = node; +} + +/* + * Get the head of a page list. + * Because redundant function calls + * are really great, and just in case + * we change the list implementation. + */ +inline static klmalloc_bin_header * __attribute__ ((always_inline)) klmalloc_list_head(klmalloc_bin_header_head *head) { + return head->first; +} + +/* }}} Lists */ +/* Skip List {{{ */ + +/* + * Skip lists are efficient + * data structures for storing + * and searching ordered data. + * + * Here, the skip lists are used + * to keep track of big bins. + */ + +/* + * Generate a random value in an appropriate range. + * This is a xor-shift RNG. + */ +static uint32_t __attribute__ ((pure)) klmalloc_skip_rand(void) { + static uint32_t x = 123456789; + static uint32_t y = 362436069; + static uint32_t z = 521288629; + static uint32_t w = 88675123; + + uint32_t t; + + t = x ^ (x << 11); + x = y; y = z; z = w; + return w = w ^ (w >> 19) ^ t ^ (t >> 8); +} + +/* + * Generate a random level for a skip node + */ +inline static int __attribute__ ((pure, always_inline)) klmalloc_random_level(void) { + int level = 0; + /* + * Keep trying to check rand() against 50% of its maximum. + * This provides 50%, 25%, 12.5%, etc. chance for each level. + */ + while (klmalloc_skip_rand() < SKIP_P && level < SKIP_MAX_LEVEL) { + ++level; + } + return level; +} + +/* + * Find best fit for a given value. + */ +static klmalloc_big_bin_header * klmalloc_skip_list_findbest(uintptr_t search_size) { + klmalloc_big_bin_header * node = &klmalloc_big_bins.head; + /* + * Loop through the skip list until we hit something > our search value. + */ + int i; + for (i = klmalloc_big_bins.level; i >= 0; --i) { + while (node->forward[i] && (node->forward[i]->size < search_size)) { + node = node->forward[i]; + if (node) + assert((node->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + } + } + /* + * This value will either be NULL (we found nothing) + * or a node (we found a minimum fit). + */ + node = node->forward[0]; + if (node) { + assert((uintptr_t)node % PAGE_SIZE == 0); + assert((node->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + } + return node; +} + +/* + * Insert a header into the skip list. + */ +static void klmalloc_skip_list_insert(klmalloc_big_bin_header * value) { + /* + * You better be giving me something valid to insert, + * or I will slit your ****ing throat. + */ + assert(value != NULL); + assert(value->head != NULL); + assert((uintptr_t)value->head > (uintptr_t)value); + if (value->size > NUM_BINS) { + assert((uintptr_t)value->head < (uintptr_t)value + value->size); + } else { + assert((uintptr_t)value->head < (uintptr_t)value + PAGE_SIZE); + } + assert((uintptr_t)value % PAGE_SIZE == 0); + assert((value->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + assert(value->size != 0); + + /* + * Starting from the head node of the bin locator... + */ + klmalloc_big_bin_header * node = &klmalloc_big_bins.head; + klmalloc_big_bin_header * update[SKIP_MAX_LEVEL + 1]; + + /* + * Loop through the skiplist to find the right place + * to insert the node (where ->forward[] > value) + */ + int i; + for (i = klmalloc_big_bins.level; i >= 0; --i) { + while (node->forward[i] && node->forward[i]->size < value->size) { + node = node->forward[i]; + if (node) + assert((node->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + } + update[i] = node; + } + node = node->forward[0]; + + /* + * Make the new skip node and update + * the forward values. + */ + if (node != value) { + int level = klmalloc_random_level(); + /* + * Get all of the nodes before this. + */ + if (level > klmalloc_big_bins.level) { + for (i = klmalloc_big_bins.level + 1; i <= level; ++i) { + update[i] = &klmalloc_big_bins.head; + } + klmalloc_big_bins.level = level; + } + + /* + * Make the new node. + */ + node = value; + + /* + * Run through and point the preceeding nodes + * for each level to the new node. + */ + for (i = 0; i <= level; ++i) { + node->forward[i] = update[i]->forward[i]; + if (node->forward[i]) + assert((node->forward[i]->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + update[i]->forward[i] = node; + } + } +} + +/* + * Delete a header from the skip list. + * Be sure you didn't change the size, or we won't be able to find it. + */ +static void klmalloc_skip_list_delete(klmalloc_big_bin_header * value) { + /* + * Debug assertions + */ + assert(value != NULL); + assert(value->head); + assert((uintptr_t)value->head > (uintptr_t)value); + if (value->size > NUM_BINS) { + assert((uintptr_t)value->head < (uintptr_t)value + value->size); + } else { + assert((uintptr_t)value->head < (uintptr_t)value + PAGE_SIZE); + } + + /* + * Starting from the bin header, again... + */ + klmalloc_big_bin_header * node = &klmalloc_big_bins.head; + klmalloc_big_bin_header * update[SKIP_MAX_LEVEL + 1]; + + /* + * Find the node. + */ + int i; + for (i = klmalloc_big_bins.level; i >= 0; --i) { + while (node->forward[i] && node->forward[i]->size < value->size) { + node = node->forward[i]; + if (node) + assert((node->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + } + update[i] = node; + } + node = node->forward[0]; + while (node != value) { + node = node->forward[0]; + } + + if (node != value) { + node = klmalloc_big_bins.head.forward[0]; + while (node->forward[0] && node->forward[0] != value) { + node = node->forward[0]; + } + node = node->forward[0]; + } + /* + * If we found the node, delete it; + * otherwise, we do nothing. + */ + if (node == value) { + for (i = 0; i <= klmalloc_big_bins.level; ++i) { + if (update[i]->forward[i] != node) { + break; + } + update[i]->forward[i] = node->forward[i]; + if (update[i]->forward[i]) { + assert((uintptr_t)(update[i]->forward[i]) % PAGE_SIZE == 0); + assert((update[i]->forward[i]->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + } + } + + while (klmalloc_big_bins.level > 0 && klmalloc_big_bins.head.forward[klmalloc_big_bins.level] == NULL) { + --klmalloc_big_bins.level; + } + } +} + +/* }}} */ +/* Stack {{{ */ +/* + * Pop an item from a block. + * Free space is stored as a stack, + * so we get a free space for a bin + * by popping a free node from the + * top of the stack. + */ +static void * klmalloc_stack_pop(klmalloc_bin_header *header) { + assert(header); + assert(header->head != NULL); + assert((uintptr_t)header->head > (uintptr_t)header); + if (header->size > NUM_BINS) { + assert((uintptr_t)header->head < (uintptr_t)header + header->size); + } else { + assert((uintptr_t)header->head < (uintptr_t)header + PAGE_SIZE); + assert((uintptr_t)header->head > (uintptr_t)header + sizeof(klmalloc_bin_header) - 1); + } + + /* + * Remove the current head and point + * the head to where the old head pointed. + */ + void *item = header->head; + uintptr_t **head = header->head; + uintptr_t *next = *head; + header->head = next; + return item; +} + +/* + * Push an item into a block. + * When we free memory, we need + * to add the freed cell back + * into the stack of free spaces + * for the block. + */ +static void klmalloc_stack_push(klmalloc_bin_header *header, void *ptr) { + assert(ptr != NULL); + assert((uintptr_t)ptr > (uintptr_t)header); + if (header->size > NUM_BINS) { + assert((uintptr_t)ptr < (uintptr_t)header + header->size); + } else { + assert((uintptr_t)ptr < (uintptr_t)header + PAGE_SIZE); + } + uintptr_t **item = (uintptr_t **)ptr; + *item = (uintptr_t *)header->head; + header->head = item; +} + +/* + * Is this cell stack empty? + * If the head of the stack points + * to NULL, we have exhausted the + * stack, so there is no more free + * space available in the block. + */ +inline static int __attribute__ ((always_inline)) klmalloc_stack_empty(klmalloc_bin_header *header) { + return header->head == NULL; +} + +/* }}} Stack */ + +/* malloc() {{{ */ +static void * __attribute__ ((malloc)) klmalloc(uintptr_t size) { + /* + * C standard implementation: + * If size is zero, we can choose do a number of things. + * This implementation will return a NULL pointer. + */ + if (__builtin_expect(size == 0, 0)) + return NULL; + + /* + * Find the appropriate bin for the requested + * allocation and start looking through that list. + */ + unsigned int bucket_id = klmalloc_bin_size(size); + + if (bucket_id < BIG_BIN) { + /* + * Small bins. + */ + klmalloc_bin_header * bin_header = klmalloc_list_head(&klmalloc_bin_head[bucket_id]); + if (!bin_header) { + /* + * Grow the heap for the new bin. + */ + bin_header = (klmalloc_bin_header*)sbrk(PAGE_SIZE); + bin_header->bin_magic = BIN_MAGIC; + assert((uintptr_t)bin_header % PAGE_SIZE == 0); + + /* + * Set the head of the stack. + */ + bin_header->head = (void*)((uintptr_t)bin_header + sizeof(klmalloc_bin_header)); + /* + * Insert the new bin at the front of + * the list of bins for this size. + */ + klmalloc_list_insert(&klmalloc_bin_head[bucket_id], bin_header); + /* + * Initialize the stack inside the bin. + * The stack is initially full, with each + * entry pointing to the next until the end + * which points to NULL. + */ + uintptr_t adj = SMALLEST_BIN_LOG + bucket_id; + uintptr_t i, available = ((PAGE_SIZE - sizeof(klmalloc_bin_header)) >> adj) - 1; + + uintptr_t **base = bin_header->head; + for (i = 0; i < available; ++i) { + /* + * Our available memory is made into a stack, with each + * piece of memory turned into a pointer to the next + * available piece. When we want to get a new piece + * of memory from this block, we just pop off a free + * spot and give its address. + */ + base[i << bucket_id] = (uintptr_t *)&base[(i + 1) << bucket_id]; + } + base[available << bucket_id] = NULL; + bin_header->size = bucket_id; + } + uintptr_t ** item = klmalloc_stack_pop(bin_header); + if (klmalloc_stack_empty(bin_header)) { + klmalloc_list_decouple(&(klmalloc_bin_head[bucket_id]),bin_header); + } + return item; + } else { + /* + * Big bins. + */ + klmalloc_big_bin_header * bin_header = klmalloc_skip_list_findbest(size); + if (bin_header) { + assert(bin_header->size >= size); + /* + * If we found one, delete it from the skip list + */ + klmalloc_skip_list_delete(bin_header); + /* + * Retreive the head of the block. + */ + uintptr_t ** item = klmalloc_stack_pop((klmalloc_bin_header *)bin_header); +#if 0 + /* + * Resize block, if necessary + */ + assert(bin_header->head == NULL); + uintptr_t old_size = bin_header->size; + //uintptr_t rsize = size; + /* + * Round the requeste size to our full required size. + */ + size = ((size + sizeof(klmalloc_big_bin_header)) / PAGE_SIZE + 1) * PAGE_SIZE - sizeof(klmalloc_big_bin_header); + assert((size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + if (bin_header->size > size * 2) { + assert(old_size != size); + /* + * If we have extra space, start splitting. + */ + bin_header->size = size; + assert(sbrk(0) >= bin_header->size + (uintptr_t)bin_header); + /* + * Make a new block at the end of the needed space. + */ + klmalloc_big_bin_header * header_new = (klmalloc_big_bin_header *)((uintptr_t)bin_header + sizeof(klmalloc_big_bin_header) + size); + assert((uintptr_t)header_new % PAGE_SIZE == 0); + memset(header_new, 0, sizeof(klmalloc_big_bin_header) + sizeof(void *)); + header_new->prev = bin_header; + if (bin_header->next) { + bin_header->next->prev = header_new; + } + header_new->next = bin_header->next; + bin_header->next = header_new; + if (klmalloc_newest_big == bin_header) { + klmalloc_newest_big = header_new; + } + header_new->size = old_size - (size + sizeof(klmalloc_big_bin_header)); + assert(((uintptr_t)header_new->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + fprintf(stderr, "Splitting %p [now %zx] at %p [%zx] from [%zx,%zx].\n", (void*)bin_header, bin_header->size, (void*)header_new, header_new->size, old_size, size); + /* + * Free the new block. + */ + klfree((void *)((uintptr_t)header_new + sizeof(klmalloc_big_bin_header))); + } +#endif + return item; + } else { + /* + * Round requested size to a set of pages, plus the header size. + */ + uintptr_t pages = (size + sizeof(klmalloc_big_bin_header)) / PAGE_SIZE + 1; + bin_header = (klmalloc_big_bin_header*)sbrk(PAGE_SIZE * pages); + bin_header->bin_magic = BIN_MAGIC; + assert((uintptr_t)bin_header % PAGE_SIZE == 0); + /* + * Give the header the remaining space. + */ + bin_header->size = pages * PAGE_SIZE - sizeof(klmalloc_big_bin_header); + assert((bin_header->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + /* + * Link the block in physical memory. + */ + bin_header->prev = klmalloc_newest_big; + if (bin_header->prev) { + bin_header->prev->next = bin_header; + } + klmalloc_newest_big = bin_header; + bin_header->next = NULL; + /* + * Return the head of the block. + */ + bin_header->head = NULL; + return (void*)((uintptr_t)bin_header + sizeof(klmalloc_big_bin_header)); + } + } +} +/* }}} */ +/* free() {{{ */ +static void klfree(void *ptr) { + /* + * C standard implementation: Do nothing when NULL is passed to free. + */ + if (__builtin_expect(ptr == NULL, 0)) { + return; + } + + /* + * Woah, woah, hold on, was this a page-aligned block? + */ + if ((uintptr_t)ptr % PAGE_SIZE == 0) { + /* + * Well howdy-do, it was. + */ + ptr = (void *)((uintptr_t)ptr - 1); + } + + /* + * Get our pointer to the head of this block by + * page aligning it. + */ + klmalloc_bin_header * header = (klmalloc_bin_header *)((uintptr_t)ptr & (uintptr_t)~PAGE_MASK); + assert((uintptr_t)header % PAGE_SIZE == 0); + + if (header->bin_magic != BIN_MAGIC) + return; + + /* + * For small bins, the bin number is stored in the size + * field of the header. For large bins, the actual size + * available in the bin is stored in this field. It's + * easy to tell which is which, though. + */ + uintptr_t bucket_id = header->size; + if (bucket_id > (uintptr_t)NUM_BINS) { + bucket_id = BIG_BIN; + klmalloc_big_bin_header *bheader = (klmalloc_big_bin_header*)header; + + assert(bheader); + assert(bheader->head == NULL); + assert((bheader->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + /* + * Coalesce forward blocks into us. + */ +#if 0 + if (bheader != klmalloc_newest_big) { + /* + * If we are not the newest big bin, there is most definitely + * something in front of us that we can read. + */ + assert((bheader->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + klmalloc_big_bin_header * next = (void *)((uintptr_t)bheader + sizeof(klmalloc_big_bin_header) + bheader->size); + assert((uintptr_t)next % PAGE_SIZE == 0); + if (next == bheader->next && next->head) { //next->size > NUM_BINS && next->head) { + /* + * If that something is an available big bin, we can + * coalesce it into us to form one larger bin. + */ + + uintptr_t old_size = bheader->size; + + klmalloc_skip_list_delete(next); + bheader->size = (uintptr_t)bheader->size + (uintptr_t)sizeof(klmalloc_big_bin_header) + next->size; + assert((bheader->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + + if (next == klmalloc_newest_big) { + /* + * If the guy in front of us was the newest, + * we are now the newest (as we are him). + */ + klmalloc_newest_big = bheader; + } else { + if (next->next) { + next->next->prev = bheader; + } + } + fprintf(stderr,"Coelesced (forwards) %p [%zx] <- %p [%zx] = %zx\n", (void*)bheader, old_size, (void*)next, next->size, bheader->size); + } + } +#endif + /* + * Coalesce backwards + */ +#if 0 + if (bheader->prev && bheader->prev->head) { + /* + * If there is something behind us, it is available, and there is nothing between + * it and us, we can coalesce ourselves into it to form a big block. + */ + if ((uintptr_t)bheader->prev + (bheader->prev->size + sizeof(klmalloc_big_bin_header)) == (uintptr_t)bheader) { + + uintptr_t old_size = bheader->prev->size; + + klmalloc_skip_list_delete(bheader->prev); + bheader->prev->size = (uintptr_t)bheader->prev->size + (uintptr_t)bheader->size + sizeof(klmalloc_big_bin_header); + assert((bheader->prev->size + sizeof(klmalloc_big_bin_header)) % PAGE_SIZE == 0); + klmalloc_skip_list_insert(bheader->prev); + if (klmalloc_newest_big == bheader) { + klmalloc_newest_big = bheader->prev; + } else { + if (bheader->next) { + bheader->next->prev = bheader->prev; + } + } + fprintf(stderr,"Coelesced (backwards) %p [%zx] <- %p [%zx] = %zx\n", (void*)bheader->prev, old_size, (void*)bheader, bheader->size, bheader->size); + /* + * If we coalesced backwards, we are done. + */ + return; + } + } +#endif + /* + * Push new space back into the stack. + */ + klmalloc_stack_push((klmalloc_bin_header *)bheader, (void *)((uintptr_t)bheader + sizeof(klmalloc_big_bin_header))); + assert(bheader->head != NULL); + /* + * Insert the block into list of available slabs. + */ + klmalloc_skip_list_insert(bheader); + } else { + /* + * If the stack is empty, we are freeing + * a block from a previously full bin. + * Return it to the busy bins list. + */ + if (klmalloc_stack_empty(header)) { + klmalloc_list_insert(&klmalloc_bin_head[bucket_id], header); + } + /* + * Push new space back into the stack. + */ + klmalloc_stack_push(header, ptr); + } +} +/* }}} */ +/* valloc() {{{ */ +static void * __attribute__ ((malloc)) klvalloc(uintptr_t size) { + /* + * Allocate a page-aligned block. + * XXX: THIS IS HORRIBLY, HORRIBLY WASTEFUL!! ONLY USE THIS + * IF YOU KNOW WHAT YOU ARE DOING! + */ + uintptr_t true_size = size + PAGE_SIZE - sizeof(klmalloc_big_bin_header); /* Here we go... */ + void * result = klmalloc(true_size); + void * out = (void *)((uintptr_t)result + (PAGE_SIZE - sizeof(klmalloc_big_bin_header))); + assert((uintptr_t)out % PAGE_SIZE == 0); + return out; +} +/* }}} */ +/* realloc() {{{ */ +static void * __attribute__ ((malloc)) klrealloc(void *ptr, uintptr_t size) { + /* + * C standard implementation: When NULL is passed to realloc, + * simply malloc the requested size and return a pointer to that. + */ + if (__builtin_expect(ptr == NULL, 0)) + return klmalloc(size); + + /* + * C standard implementation: For a size of zero, free the + * pointer and return NULL, allocating no new memory. + */ + if (__builtin_expect(size == 0, 0)) + { + free(ptr); + return NULL; + } + + /* + * Find the bin for the given pointer + * by aligning it to a page. + */ + klmalloc_bin_header * header_old = (void *)((uintptr_t)ptr & (uintptr_t)~PAGE_MASK); + if (header_old->bin_magic != BIN_MAGIC) { + assert(0 && "Bad magic on realloc."); + return NULL; + } + + uintptr_t old_size = header_old->size; + if (old_size < (uintptr_t)BIG_BIN) { + /* + * If we are copying from a small bin, + * we need to get the size of the bin + * from its id. + */ + old_size = (1UL << (SMALLEST_BIN_LOG + old_size)); + } + + /* + * (This will only happen for a big bin, mathematically speaking) + * If we still have room in our bin for the additonal space, + * we don't need to do anything. + */ + if (old_size >= size) { + + /* + * TODO: Break apart blocks here, which is far more important + * than breaking them up on allocations. + */ + return ptr; + } + + /* + * Reallocate more memory. + */ + void * newptr = klmalloc(size); + if (__builtin_expect(newptr != NULL, 1)) { + + /* + * Copy the old value into the new value. + * Be sure to only copy as much as was in + * the old block. + */ + memcpy(newptr, ptr, old_size); + klfree(ptr); + return newptr; + } + + /* + * We failed to allocate more memory, + * which means we're probably out. + * + * Bail and return NULL. + */ + return NULL; +} +/* }}} */ +/* calloc() {{{ */ +static void * __attribute__ ((malloc)) klcalloc(uintptr_t nmemb, uintptr_t size) { + /* + * Allocate memory and zero it before returning + * a pointer to the newly allocated memory. + * + * Implemented by way of a simple malloc followed + * by a memset to 0x00 across the length of the + * requested memory chunk. + */ + + void *ptr = klmalloc(nmemb * size); + if (__builtin_expect(ptr != NULL, 1)) + memset(ptr,0x00,nmemb * size); + return ptr; +} +/* }}} */ diff --git a/kernel/mem/mem.c b/kernel/mem/mem.c new file mode 100644 index 00000000..7d344c91 --- /dev/null +++ b/kernel/mem/mem.c @@ -0,0 +1,564 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2012 Markus Schober + * + * Kernel Memory Manager + */ + +#include +#include +#include +#include +#include +#include +#include + +#define KERNEL_HEAP_INIT 0x00800000 +#define KERNEL_HEAP_END 0x20000000 + +extern void *end; +uintptr_t placement_pointer = (uintptr_t)&end; +uintptr_t heap_end = (uintptr_t)NULL; +uintptr_t kernel_heap_alloc_point = KERNEL_HEAP_INIT; + +//static volatile uint8_t frame_alloc_lock = 0; +static spin_lock_t frame_alloc_lock = { 0 }; +uint32_t first_n_frames(int n); + +void +kmalloc_startat( + uintptr_t address + ) { + placement_pointer = address; +} + +/* + * kmalloc() is the kernel's dumb placement allocator + */ +uintptr_t +kmalloc_real( + size_t size, + int align, + uintptr_t * phys + ) { + if (heap_end) { + void * address; + if (align) { + address = valloc(size); + } else { + address = malloc(size); + } + if (phys) { + if (align && size >= 0x3000) { + debug_print(NOTICE, "Requested large aligned alloc of size 0x%x", size); + for (uintptr_t i = (uintptr_t)address; i < (uintptr_t)address + size; i += 0x1000) { + clear_frame(map_to_physical(i)); + } + /* XXX This is going to get touchy... */ + spin_lock(frame_alloc_lock); + uint32_t index = first_n_frames((size + 0xFFF) / 0x1000); + if (index == 0xFFFFFFFF) { + spin_unlock(frame_alloc_lock); + return 0; + } + for (unsigned int i = 0; i < (size + 0xFFF) / 0x1000; ++i) { + set_frame((index + i) * 0x1000); + page_t * page = get_page((uintptr_t)address + (i * 0x1000),0,kernel_directory); + ASSUME(page != NULL); + page->frame = index + i; + page->writethrough = 1; + page->cachedisable = 1; + } + spin_unlock(frame_alloc_lock); + } + *phys = map_to_physical((uintptr_t)address); + } + return (uintptr_t)address; + } + + if (align && (placement_pointer & 0xFFFFF000)) { + placement_pointer &= 0xFFFFF000; + placement_pointer += 0x1000; + } + if (phys) { + *phys = placement_pointer; + } + uintptr_t address = placement_pointer; + placement_pointer += size; + return (uintptr_t)address; +} +/* + * Normal + */ +uintptr_t +kmalloc( + size_t size + ) { + return kmalloc_real(size, 0, NULL); +} +/* + * Aligned + */ +uintptr_t +kvmalloc( + size_t size + ) { + return kmalloc_real(size, 1, NULL); +} +/* + * With a physical address + */ +uintptr_t +kmalloc_p( + size_t size, + uintptr_t *phys + ) { + return kmalloc_real(size, 0, phys); +} +/* + * Aligned, with a physical address + */ +uintptr_t +kvmalloc_p( + size_t size, + uintptr_t *phys + ) { + return kmalloc_real(size, 1, phys); +} + +/* + * Frame Allocation + */ + +uint32_t *frames; +uint32_t nframes; + +#define INDEX_FROM_BIT(b) (b / 0x20) +#define OFFSET_FROM_BIT(b) (b % 0x20) + +void +set_frame( + uintptr_t frame_addr + ) { + if (frame_addr < nframes * 4 * 0x400) { + uint32_t frame = frame_addr / 0x1000; + uint32_t index = INDEX_FROM_BIT(frame); + uint32_t offset = OFFSET_FROM_BIT(frame); + frames[index] |= ((uint32_t)0x1 << offset); + } +} + +void +clear_frame( + uintptr_t frame_addr + ) { + uint32_t frame = frame_addr / 0x1000; + uint32_t index = INDEX_FROM_BIT(frame); + uint32_t offset = OFFSET_FROM_BIT(frame); + frames[index] &= ~((uint32_t)0x1 << offset); +} + +uint32_t test_frame(uintptr_t frame_addr) { + uint32_t frame = frame_addr / 0x1000; + uint32_t index = INDEX_FROM_BIT(frame); + uint32_t offset = OFFSET_FROM_BIT(frame); + return (frames[index] & ((uint32_t)0x1 << offset)); +} + +uint32_t first_n_frames(int n) { + for (uint32_t i = 0; i < nframes * 0x1000; i += 0x1000) { + int bad = 0; + for (int j = 0; j < n; ++j) { + if (test_frame(i + 0x1000 * j)) { + bad = j+1; + } + } + if (!bad) { + return i / 0x1000; + } + } + return 0xFFFFFFFF; +} + +uint32_t first_frame(void) { + uint32_t i, j; + + for (i = 0; i < INDEX_FROM_BIT(nframes); ++i) { + if (frames[i] != 0xFFFFFFFF) { + for (j = 0; j < 32; ++j) { + uint32_t testFrame = (uint32_t)0x1 << j; + if (!(frames[i] & testFrame)) { + return i * 0x20 + j; + } + } + } + } + + debug_print(CRITICAL, "System claims to be out of usable memory, which means we probably overwrote the page frames.\033[0m"); + + if (debug_video_crash) { + char * msgs[] = {"Out of memory.", NULL}; + debug_video_crash(msgs); + } + +#if 0 + signal_t * sig = malloc(sizeof(signal_t)); + sig->handler = current_process->signals.functions[SIGSEGV]; + sig->signum = SIGSEGV; + handle_signal((process_t *)current_process, sig); +#endif + + STOP; + + return -1; +} + +void +alloc_frame( + page_t *page, + int is_kernel, + int is_writeable + ) { + ASSUME(page != NULL); + if (page->frame != 0) { + page->present = 1; + page->rw = (is_writeable == 1) ? 1 : 0; + page->user = (is_kernel == 1) ? 0 : 1; + return; + } else { + spin_lock(frame_alloc_lock); + uint32_t index = first_frame(); + assert(index != (uint32_t)-1 && "Out of frames."); + set_frame(index * 0x1000); + page->frame = index; + spin_unlock(frame_alloc_lock); + page->present = 1; + page->rw = (is_writeable == 1) ? 1 : 0; + page->user = (is_kernel == 1) ? 0 : 1; + } +} + +void +dma_frame( + page_t *page, + int is_kernel, + int is_writeable, + uintptr_t address + ) { + ASSUME(page != NULL); + /* Page this address directly */ + page->present = 1; + page->rw = (is_writeable) ? 1 : 0; + page->user = (is_kernel) ? 0 : 1; + page->frame = address / 0x1000; + set_frame(address); +} + +void +free_frame( + page_t *page + ) { + uint32_t frame; + if (!(frame = page->frame)) { + assert(0); + return; + } else { + clear_frame(frame * 0x1000); + page->frame = 0x0; + } +} + +uintptr_t memory_use(void ) { + uintptr_t ret = 0; + uint32_t i, j; + for (i = 0; i < INDEX_FROM_BIT(nframes); ++i) { + for (j = 0; j < 32; ++j) { + uint32_t testFrame = (uint32_t)0x1 << j; + if (frames[i] & testFrame) { + ret++; + } + } + } + return ret * 4; +} + +uintptr_t memory_total(){ + return nframes * 4; +} + +void paging_install(uint32_t memsize) { + nframes = memsize / 4; + frames = (uint32_t *)kmalloc(INDEX_FROM_BIT(nframes * 8)); + memset(frames, 0, INDEX_FROM_BIT(nframes * 8)); + + uintptr_t phys; + kernel_directory = (page_directory_t *)kvmalloc_p(sizeof(page_directory_t),&phys); + memset(kernel_directory, 0, sizeof(page_directory_t)); +} + +void paging_mark_system(uint64_t addr) { + set_frame(addr); +} + +void paging_finalize(void) { + debug_print(INFO, "Placement pointer is at 0x%x", placement_pointer); +#if 1 + get_page(0,1,kernel_directory)->present = 0; + set_frame(0); + for (uintptr_t i = 0x1000; i < 0x80000; i += 0x1000) { +#else + for (uintptr_t i = 0x0; i < 0x80000; i += 0x1000) { +#endif + dma_frame(get_page(i, 1, kernel_directory), 1, 0, i); + } + for (uintptr_t i = 0x80000; i < 0x100000; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 1, 0, i); + } + for (uintptr_t i = 0x100000; i < placement_pointer + 0x3000; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 1, 0, i); + } + debug_print(INFO, "Mapping VGA text-mode directly."); + for (uintptr_t j = 0xb8000; j < 0xc0000; j += 0x1000) { + dma_frame(get_page(j, 0, kernel_directory), 0, 1, j); + } + isrs_install_handler(14, page_fault); + kernel_directory->physical_address = (uintptr_t)kernel_directory->physical_tables; + + uintptr_t tmp_heap_start = KERNEL_HEAP_INIT; + + if (tmp_heap_start <= placement_pointer + 0x3000) { + debug_print(ERROR, "Foo: 0x%x, 0x%x", tmp_heap_start, placement_pointer + 0x3000); + tmp_heap_start = placement_pointer + 0x100000; + kernel_heap_alloc_point = tmp_heap_start; + } + + /* Kernel Heap Space */ + for (uintptr_t i = placement_pointer + 0x3000; i < tmp_heap_start; i += 0x1000) { + alloc_frame(get_page(i, 1, kernel_directory), 1, 0); + } + /* And preallocate the page entries for all the rest of the kernel heap as well */ + for (uintptr_t i = tmp_heap_start; i < KERNEL_HEAP_END; i += 0x1000) { + get_page(i, 1, kernel_directory); + } + + debug_print(NOTICE, "Setting directory."); + current_directory = clone_directory(kernel_directory); + switch_page_directory(kernel_directory); +} + +uintptr_t map_to_physical(uintptr_t virtual) { + uintptr_t remaining = virtual % 0x1000; + uintptr_t frame = virtual / 0x1000; + uintptr_t table = frame / 1024; + uintptr_t subframe = frame % 1024; + + if (current_directory->tables[table]) { + page_t * p = ¤t_directory->tables[table]->pages[subframe]; + return p->frame * 0x1000 + remaining; + } else { + return 0; + } +} + +void debug_print_directory(page_directory_t * arg) { + page_directory_t * current_directory = arg; + debug_print(INSANE, " ---- [k:0x%x u:0x%x]", kernel_directory, current_directory); + for (uintptr_t i = 0; i < 1024; ++i) { + if (!current_directory->tables[i] || (uintptr_t)current_directory->tables[i] == (uintptr_t)0xFFFFFFFF) { + continue; + } + if (kernel_directory->tables[i] == current_directory->tables[i]) { + debug_print(INSANE, " 0x%x - kern [0x%x/0x%x] 0x%x", current_directory->tables[i], ¤t_directory->tables[i], &kernel_directory->tables[i], i * 0x1000 * 1024); + for (uint16_t j = 0; j < 1024; ++j) { +#if 1 + page_t * p= ¤t_directory->tables[i]->pages[j]; + if (p->frame) { + debug_print(INSANE, " k 0x%x 0x%x %s", (i * 1024 + j) * 0x1000, p->frame * 0x1000, p->present ? "[present]" : ""); + } +#endif + } + } else { + debug_print(INSANE, " 0x%x - user [0x%x] 0x%x [0x%x]", current_directory->tables[i], ¤t_directory->tables[i], i * 0x1000 * 1024, kernel_directory->tables[i]); + for (uint16_t j = 0; j < 1024; ++j) { +#if 1 + page_t * p= ¤t_directory->tables[i]->pages[j]; + if (p->frame) { + debug_print(INSANE, " 0x%x 0x%x %s", (i * 1024 + j) * 0x1000, p->frame * 0x1000, p->present ? "[present]" : ""); + } +#endif + } + } + } + debug_print(INFO, " ---- [done]"); +} + +void +switch_page_directory( + page_directory_t * dir + ) { + current_directory = dir; + asm volatile ( + "mov %0, %%cr3\n" + "mov %%cr0, %%eax\n" + "orl $0x80000000, %%eax\n" + "mov %%eax, %%cr0\n" + :: "r"(dir->physical_address) + : "%eax"); +} + +void invalidate_page_tables(void) { + asm volatile ( + "movl %%cr3, %%eax\n" + "movl %%eax, %%cr3\n" + ::: "%eax"); +} + +void invalidate_tables_at(uintptr_t addr) { + asm volatile ( + "movl %0,%%eax\n" + "invlpg (%%eax)\n" + :: "r"(addr) : "%eax"); +} + +page_t * +get_page( + uintptr_t address, + int make, + page_directory_t * dir + ) { + address /= 0x1000; + uint32_t table_index = address / 1024; + if (dir->tables[table_index]) { + return &dir->tables[table_index]->pages[address % 1024]; + } else if(make) { + uint32_t temp; + dir->tables[table_index] = (page_table_t *)kvmalloc_p(sizeof(page_table_t), (uintptr_t *)(&temp)); + ASSUME(dir->tables[table_index] != NULL); + memset(dir->tables[table_index], 0, sizeof(page_table_t)); + dir->physical_tables[table_index] = temp | 0x7; /* Present, R/w, User */ + return &dir->tables[table_index]->pages[address % 1024]; + } else { + return 0; + } +} + +void +page_fault( + struct regs *r) { + ASSUME(r != NULL); + uint32_t faulting_address; + asm volatile("mov %%cr2, %0" : "=r"(faulting_address)); + + if (r->eip == SIGNAL_RETURN) { + return_from_signal_handler(); + } else if (r->eip == THREAD_RETURN) { + debug_print(INFO, "Returned from thread."); + kexit(0); + } + +#if 1 + int present = !(r->err_code & 0x1) ? 1 : 0; + int rw = r->err_code & 0x2 ? 1 : 0; + int user = r->err_code & 0x4 ? 1 : 0; + int reserved = r->err_code & 0x8 ? 1 : 0; + int id = r->err_code & 0x10 ? 1 : 0; + + debug_print(ERROR, "\033[1;37;41mSegmentation fault. (p:%d,rw:%d,user:%d,res:%d,id:%d) at 0x%x eip: 0x%x pid=%d,%d [%s]\033[0m", + present, rw, user, reserved, id, faulting_address, r->eip, current_process->id, current_process->group, current_process->name); + + if (r->eip < heap_end) { + /* find closest symbol */ + char * closest = NULL; + size_t distance = 0xFFFFFFFF; + uintptr_t addr = 0; + + if (modules_get_symbols()) { + list_t * hash_keys = hashmap_keys(modules_get_symbols()); + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + uintptr_t a = (uintptr_t)hashmap_get(modules_get_symbols(), key); + + if (!a) continue; + + size_t d; + if (a <= r->eip) { + d = r->eip - a; + } else { + d = a - r->eip; + } + if (d < distance) { + closest = key; + distance = d; + addr = a; + } + } + free(hash_keys); + + debug_print(ERROR, "\033[1;31mClosest symbol to faulting address:\033[0m %s [0x%x]", closest, addr); + + hash_keys = hashmap_keys(modules_get_list()); + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + module_data_t * m = (module_data_t *)hashmap_get(modules_get_list(), key); + + if ((r->eip >= (uintptr_t)m->bin_data) && (r->eip < m->end)) { + debug_print(ERROR, "\033[1;31mIn module:\033[0m %s (starts at 0x%x)", m->mod_info->name, m->bin_data); + break; + } + } + free(hash_keys); + + debug_print(ERROR, "User EIP: 0x%x", current_process->syscall_registers->eip); + } + + } else { + debug_print(ERROR, "\033[1;31m(In userspace)\033[0m"); + } + +#endif + + signal_t * sig = malloc(sizeof(signal_t)); + sig->handler = current_process->signals.functions[SIGSEGV]; + sig->signum = SIGSEGV; + handle_signal((process_t *)current_process, sig); + +} + +/* + * Heap + * Stop using kalloc and friends after installing the heap + * otherwise shit will break. I've conveniently broken + * kalloc when installing the heap, just for those of you + * who feel the need to screw up. + */ + + +void heap_install(void ) { + heap_end = (placement_pointer + 0x1000) & ~0xFFF; +} + +void * sbrk(uintptr_t increment) { + assert((increment % 0x1000 == 0) && "Kernel requested to expand heap by a non-page-multiple value"); + assert((heap_end % 0x1000 == 0) && "Kernel heap is not page-aligned!"); + assert((heap_end + increment <= KERNEL_HEAP_END - 1) && "The kernel has attempted to allocate beyond the end of its heap."); + uintptr_t address = heap_end; + + if (heap_end + increment > kernel_heap_alloc_point) { + debug_print(INFO, "Hit the end of available kernel heap, going to allocate more (at 0x%x, want to be at 0x%x)", heap_end, heap_end + increment); + for (uintptr_t i = heap_end; i < heap_end + increment; i += 0x1000) { + debug_print(INFO, "Allocating frame at 0x%x...", i); + page_t * page = get_page(i, 0, kernel_directory); + assert(page && "Kernel heap allocation fault."); + alloc_frame(page, 1, 0); + } + invalidate_page_tables(); + debug_print(INFO, "Done."); + } + + heap_end += increment; + memset((void *)address, 0x0, increment); + return (void *)address; +} + diff --git a/kernel/mem/shm.c b/kernel/mem/shm.c new file mode 100644 index 00000000..89b63274 --- /dev/null +++ b/kernel/mem/shm.c @@ -0,0 +1,369 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2012-2014 Kevin Lange + * Copyright (C) 2012 Markus Schober + * + * Shared Memory + */ +#include +#include +#include +#include +#include +#include +#include + + +//static volatile uint8_t bsl; // big shm lock +static spin_lock_t bsl; // big shm lock +tree_t * shm_tree = NULL; + + +void shm_install(void) { + debug_print(NOTICE, "Installing shared memory layer..."); + shm_tree = tree_create(); + tree_set_root(shm_tree, NULL); +} + + +/* Accessors */ + + +static shm_node_t * _get_node(char * shm_path, int create, tree_node_t * from) { + + char *pch, *save; + pch = strtok_r(shm_path, SHM_PATH_SEPARATOR, &save); + + tree_node_t * tnode = from; + foreach(node, tnode->children) { + tree_node_t * _node = (tree_node_t *)node->value; + shm_node_t * snode = (shm_node_t *)_node->value; + + if (!strcmp(snode->name, pch)) { + if (*save == '\0') { + return snode; + } + return _get_node(save, create, _node); + } + } + + /* The next node in sequence was not found */ + if (create) { + shm_node_t * nsnode = malloc(sizeof(shm_node_t)); + memcpy(nsnode->name, pch, strlen(pch) + 1); + nsnode->chunk = NULL; + + tree_node_t * nnode = tree_node_insert_child(shm_tree, from, nsnode); + + if (*save == '\0') { + return nsnode; + } + + return _get_node(save, create, nnode); + } else { + return NULL; + } +} + +static shm_node_t * get_node (char * shm_path, int create) { + char * _path = malloc(strlen(shm_path)+1); + memcpy(_path, shm_path, strlen(shm_path)+1); + + shm_node_t * node = _get_node(_path, create, shm_tree->root); + + free(_path); + return node; +} + + +/* Create and Release */ + + +static shm_chunk_t * create_chunk (shm_node_t * parent, size_t size) { + debug_print(WARNING, "Size supplied to create_chunk was 0"); + if (!size) return NULL; + + shm_chunk_t *chunk = malloc(sizeof(shm_chunk_t)); + if (chunk == NULL) { + debug_print(ERROR, "Failed to allocate a shm_chunk_t!"); + return NULL; + } + + chunk->parent = parent; + chunk->lock = 0; + chunk->ref_count = 1; + + chunk->num_frames = (size / 0x1000) + ((size % 0x1000) ? 1 : 0); + chunk->frames = malloc(sizeof(uintptr_t) * chunk->num_frames); + if (chunk->frames == NULL) { + debug_print(ERROR, "Failed to allocate uintptr_t[%d]", chunk->num_frames); + free(chunk); + return NULL; + } + + /* Now grab some frames for this guy. */ + for (uint32_t i = 0; i < chunk->num_frames; i++) { + page_t tmp = {0,0,0,0,0,0,0}; + alloc_frame(&tmp, 0, 0); + chunk->frames[i] = tmp.frame; +#if 0 + debug_print(WARNING, "Using frame 0x%x for chunk[%d] (name=%s)", tmp.frame * 0x1000, i, parent->name); +#endif + } + + return chunk; +} + +static int release_chunk (shm_chunk_t * chunk) { + if (chunk) { + chunk->ref_count--; + + /* Does the chunk need to be freed? */ + if (chunk->ref_count < 1) { +#if 0 + debug_print(INFO, "Freeing chunk with name %s", chunk->parent->name); +#endif + + /* First, free the frames used by this chunk */ + for (uint32_t i = 0; i < chunk->num_frames; i++) { + clear_frame(chunk->frames[i] * 0x1000); + } + + /* Then, get rid of the damn thing */ + chunk->parent->chunk = NULL; + free(chunk->frames); + free(chunk); + } + + return 0; + } + + return -1; +} + + +/* Mapping and Unmapping */ + +static uintptr_t proc_sbrk(uint32_t num_pages, process_t * proc) { + uintptr_t initial = proc->image.shm_heap; + assert(!(initial & 0xFFF) && "shm_heap not page-aligned!"); + + if (initial % 0x1000) { + initial += 0x1000 - (initial % 0x1000); + proc->image.shm_heap = initial; + } + proc->image.shm_heap += num_pages * 0x1000; + assert(!(proc->image.shm_heap & 0xFFF) && "math is wrong, dumbass"); + + return initial; +} + +static void * map_in (shm_chunk_t * chunk, process_t * proc) { + if (!chunk) { + return NULL; + } + + shm_mapping_t * mapping = malloc(sizeof(shm_mapping_t)); + mapping->chunk = chunk; + mapping->num_vaddrs = chunk->num_frames; + mapping->vaddrs = malloc(sizeof(uintptr_t) * mapping->num_vaddrs); + + debug_print(INFO, "want %d bytes, running through mappings...", mapping->num_vaddrs * 0x1000); + uintptr_t last_address = SHM_START; + foreach(node, proc->shm_mappings) { + shm_mapping_t * m = node->value; + if (m->vaddrs[0] > last_address) { + size_t gap = (uintptr_t)m->vaddrs[0] - last_address; + debug_print(INFO, "gap found at 0x%x of size %d", last_address, gap); + if (gap >= mapping->num_vaddrs * 0x1000) { + debug_print(INFO, "Gap is sufficient, we can insert here."); + + /* Map the gap */ + for (unsigned int i = 0; i < chunk->num_frames; ++i) { + page_t * page = get_page(last_address + i * 0x1000, 1, proc->thread.page_directory); + page->frame = chunk->frames[i]; + alloc_frame(page, 0, 1); + invalidate_tables_at(last_address + i * 0x1000); + mapping->vaddrs[i] = last_address + i * 0x1000; + } + + /* Insert us before this node */ + list_insert_before(proc->shm_mappings, node, mapping); + + return (void *)mapping->vaddrs[0]; + } + } + last_address = m->vaddrs[0] + m->num_vaddrs * 0x1000; + debug_print(INFO, "[0x%x:0x%x] %s", m->vaddrs[0], last_address, m->chunk->parent->name); + } + if (proc->image.shm_heap > last_address) { + size_t gap = proc->image.shm_heap - last_address; + debug_print(INFO, "gap found at 0x%x of size %d", last_address, gap); + if (gap >= mapping->num_vaddrs * 0x1000) { + debug_print(INFO, "Gap is sufficient, we can insert here."); + + for (unsigned int i = 0; i < chunk->num_frames; ++i) { + page_t * page = get_page(last_address + i * 0x1000, 1, proc->thread.page_directory); + page->frame = chunk->frames[i]; + alloc_frame(page, 0, 1); + invalidate_tables_at(last_address + i * 0x1000); + mapping->vaddrs[i] = last_address + i * 0x1000; + } + + list_insert(proc->shm_mappings, mapping); + + return (void *)mapping->vaddrs[0]; + } else { + debug_print(INFO, "should be more efficient here - there is space available, but we are not going to use it"); + } + } + + + for (uint32_t i = 0; i < chunk->num_frames; i++) { + uintptr_t new_vpage = proc_sbrk(1, proc); + assert(new_vpage % 0x1000 == 0); + + page_t * page = get_page(new_vpage, 1, proc->thread.page_directory); + assert(page && "Page not allocated by sys_sbrk?"); + + page->frame = chunk->frames[i]; + alloc_frame(page, 0, 1); + invalidate_tables_at(new_vpage); + mapping->vaddrs[i] = new_vpage; + +#if 0 + debug_print(INFO, "mapping vaddr 0x%x --> #%d", new_vpage, page->frame); +#endif + } + + list_insert(proc->shm_mappings, mapping); + + return (void *)mapping->vaddrs[0]; +} + +static size_t chunk_size (shm_chunk_t * chunk) { + return (size_t)(chunk->num_frames * 0x1000); +} + + +/* Kernel-Facing Functions and Syscalls */ + + +void * shm_obtain (char * path, size_t * size) { + spin_lock(bsl); + process_t * proc = (process_t *)current_process; + + if (proc->group != 0) { + proc = process_from_pid(proc->group); + } + + shm_node_t * node = get_node(path, 1); // (if it exists, just get it) + assert(node && "shm_node_t not created by get_node"); + shm_chunk_t * chunk = node->chunk; + + if (chunk == NULL) { + /* There's no chunk for that key -- we need to allocate it! */ + + debug_print(NOTICE, "Allocating a new shmem chunk for process %d", proc->id); + + if (size == 0) { + // The process doesn't want a chunk...? + spin_unlock(bsl); + return NULL; + } + + chunk = create_chunk(node, *size); + if (chunk == NULL) { + debug_print(ERROR, "Could not allocate a shm_chunk_t"); + spin_unlock(bsl); + return NULL; + } + + node->chunk = chunk; + } else { + /* New accessor! */ + chunk->ref_count++; + } + void * vshm_start = map_in(chunk, proc); + *size = chunk_size(chunk); + + spin_unlock(bsl); + invalidate_page_tables(); + + return vshm_start; +} + +int shm_release (char * path) { + spin_lock(bsl); + process_t * proc = (process_t *)current_process; + + if (proc->group != 0) { + proc = process_from_pid(proc->group); + } + + /* First, find the right chunk */ + shm_node_t * _node = get_node(path, 0); + if (!_node) { + spin_unlock(bsl); + return 1; + } + shm_chunk_t * chunk = _node->chunk; + + /* Next, find the proc's mapping for that chunk */ + node_t * node = NULL; + foreach (n, proc->shm_mappings) { + shm_mapping_t * m = (shm_mapping_t *)n->value; + if (m->chunk == chunk) { + node = n; + break; + } + } + if (node == NULL) { + spin_unlock(bsl); + return 1; + } + + shm_mapping_t * mapping = (shm_mapping_t *)node->value; + + /* Clear the mappings from the process's address space */ + for (uint32_t i = 0; i < mapping->num_vaddrs; i++) { + page_t * page = get_page(mapping->vaddrs[i], 0, proc->thread.page_directory); + assert(page && "Shared memory mapping was invalid!"); + + memset(page, 0, sizeof(page_t)); + } + invalidate_page_tables(); + + /* Clean up */ + release_chunk(chunk); + list_delete(proc->shm_mappings, node); + free(node); + free(mapping); + + spin_unlock(bsl); + return 0; +} + +/* This function should only be called if the process's address space + * is about to be destroyed -- chunks will not be unmounted therefrom ! */ +void shm_release_all (process_t * proc) { + spin_lock(bsl); + + node_t * node; + while ((node = list_pop(proc->shm_mappings)) != NULL) { + shm_mapping_t * mapping = node->value; + release_chunk(mapping->chunk); + free(mapping); + free(node); + } + + /* Empty, but don't free, the mappings list */ + list_free(proc->shm_mappings); + proc->shm_mappings->head = proc->shm_mappings->tail = NULL; + proc->shm_mappings->length = 0; + + spin_unlock(bsl); +} + + diff --git a/kernel/misc/args.c b/kernel/misc/args.c new file mode 100644 index 00000000..93f7567d --- /dev/null +++ b/kernel/misc/args.c @@ -0,0 +1,91 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2013 Kevin Lange + * + * Kernel Argument Manager + * + * Arguments to the kernel are provided from the bootloader and + * provide information such as what mode to pass to init, or what + * hard disk partition should be mounted as root. + * + * This module provides access + */ +#include +#include +#include +#include +#include + +char * cmdline = NULL; + +hashmap_t * kernel_args_map = NULL; + +/** + * Check if an argument was provided to the kernel. If the argument is + * a simple switch, a response of 1 can be considered "on" for that + * argument; otherwise, this just notes that the argument was present, + * so the caller should check whether it is correctly set. + */ +int args_present(char * karg) { + if (!kernel_args_map) return 0; /* derp */ + + return hashmap_has(kernel_args_map, karg); +} + +/** + * Return the value associated with an argument provided to the kernel. + */ +char * args_value(char * karg) { + if (!kernel_args_map) return 0; /* derp */ + + return hashmap_get(kernel_args_map, karg); +} + +/** + * Parse the given arguments to the kernel. + * + * @param arg A string containing all arguments, separated by spaces. + */ +void args_parse(char * _arg) { + /* Sanity check... */ + if (!_arg) { return; } + + char * arg = strdup(_arg); + char * argv[1024]; + int argc = tokenize(arg, " ", argv); + + /* New let's parse the tokens into the arguments list so we can index by key */ + + if (!kernel_args_map) { + kernel_args_map = hashmap_create(10); + } + + for (int i = 0; i < argc; ++i) { + char * c = strdup(argv[i]); + + char * name; + char * value; + + name = c; + value = NULL; + /* Find the first = and replace it with a null */ + char * v = c; + while (*v) { + if (*v == '=') { + *v = '\0'; + v++; + value = v; + goto _break; + } + v++; + } + +_break: + hashmap_set(kernel_args_map, name, value); + } + + free(arg); + +} + diff --git a/kernel/misc/elf.c b/kernel/misc/elf.c new file mode 100644 index 00000000..771861ae --- /dev/null +++ b/kernel/misc/elf.c @@ -0,0 +1,322 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * + * ELF Static Executable Loader + * + */ + +#include +#include +#include +#include +#include + +int exec_elf(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp) { + Elf32_Header header; + + read_fs(file, 0, sizeof(Elf32_Header), (uint8_t *)&header); + + if (header.e_ident[0] != ELFMAG0 || + header.e_ident[1] != ELFMAG1 || + header.e_ident[2] != ELFMAG2 || + header.e_ident[3] != ELFMAG3) { + debug_print(ERROR, "Not a valid ELF executable."); + close_fs(file); + return -1; + } + + if (file->mask & 0x800) { + debug_print(WARNING, "setuid binary executed [%s, uid:%d]", file->name, file->uid); + current_process->user = file->uid; + } + + for (uintptr_t x = 0; x < (uint32_t)header.e_phentsize * header.e_phnum; x += header.e_phentsize) { + Elf32_Phdr phdr; + read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr); + if (phdr.p_type == PT_DYNAMIC) { + /* Dynamic */ + close_fs(file); + + /* Find interpreter? */ + debug_print(WARNING, "Dynamic executable"); + + unsigned int nargc = argc + 3; + char * args[nargc+1]; + args[0] = "ld.so"; + args[1] = "-e"; + args[2] = strdup(current_process->name); + int j = 3; + for (int i = 0; i < argc; ++i, ++j) { + args[j] = argv[i]; + } + args[j] = NULL; + + fs_node_t * file = kopen("/lib/ld.so",0); + if (!file) return -1; + + return exec_elf(NULL, file, nargc, args, env, 1); + } + } + + uintptr_t entry = (uintptr_t)header.e_entry; + uintptr_t base_addr = 0xFFFFFFFF; + uintptr_t end_addr = 0x0; + + for (uintptr_t x = 0; x < (uint32_t)header.e_phentsize * header.e_phnum; x += header.e_phentsize) { + Elf32_Phdr phdr; + read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr); + if (phdr.p_type == PT_LOAD) { + if (phdr.p_vaddr < base_addr) { + base_addr = phdr.p_vaddr; + } + if (phdr.p_memsz + phdr.p_vaddr > end_addr) { + end_addr = phdr.p_memsz + phdr.p_vaddr; + } + } + } + + current_process->image.entry = base_addr; + current_process->image.size = end_addr - base_addr; + + release_directory_for_exec(current_directory); + invalidate_page_tables(); + + + for (uintptr_t x = 0; x < (uint32_t)header.e_phentsize * header.e_phnum; x += header.e_phentsize) { + Elf32_Phdr phdr; + read_fs(file, header.e_phoff + x, sizeof(Elf32_Phdr), (uint8_t *)&phdr); + if (phdr.p_type == PT_LOAD) { + for (uintptr_t i = phdr.p_vaddr; i < phdr.p_vaddr + phdr.p_memsz; i += 0x1000) { + /* This doesn't care if we already allocated this page */ + alloc_frame(get_page(i, 1, current_directory), 0, 1); + invalidate_tables_at(i); + } + IRQ_RES; + read_fs(file, phdr.p_offset, phdr.p_filesz, (uint8_t *)phdr.p_vaddr); + IRQ_OFF; + size_t r = phdr.p_filesz; + while (r < phdr.p_memsz) { + *(char *)(phdr.p_vaddr + r) = 0; + r++; + } + } + } + + close_fs(file); + + for (uintptr_t stack_pointer = USER_STACK_BOTTOM; stack_pointer < USER_STACK_TOP; stack_pointer += 0x1000) { + alloc_frame(get_page(stack_pointer, 1, current_directory), 0, 1); + invalidate_tables_at(stack_pointer); + } + + /* Collect arguments */ + int envc = 0; + for (envc = 0; env[envc] != NULL; ++envc); + + /* Format auxv */ + Elf32_auxv auxv[] = { + {256, 0xDEADBEEF}, + {0, 0} + }; + int auxvc = 0; + for (auxvc = 0; auxv[auxvc].id != 0; ++auxvc); + auxvc++; + + uintptr_t heap = current_process->image.entry + current_process->image.size; + while (heap & 0xFFF) heap++; + alloc_frame(get_page(heap, 1, current_directory), 0, 1); + invalidate_tables_at(heap); + char ** argv_ = (char **)heap; + heap += sizeof(char *) * (argc + 1); + char ** env_ = (char **)heap; + heap += sizeof(char *) * (envc + 1); + void * auxv_ptr = (void *)heap; + heap += sizeof(Elf32_auxv) * (auxvc); + + for (int i = 0; i < argc; ++i) { + size_t size = strlen(argv[i]) * sizeof(char) + 1; + for (uintptr_t x = heap; x < heap + size + 0x1000; x += 0x1000) { + alloc_frame(get_page(x, 1, current_directory), 0, 1); + } + invalidate_tables_at(heap); + argv_[i] = (char *)heap; + memcpy((void *)heap, argv[i], size); + heap += size; + } + /* Don't forget the NULL at the end of that... */ + argv_[argc] = 0; + + for (int i = 0; i < envc; ++i) { + size_t size = strlen(env[i]) * sizeof(char) + 1; + for (uintptr_t x = heap; x < heap + size + 0x1000; x += 0x1000) { + alloc_frame(get_page(x, 1, current_directory), 0, 1); + } + invalidate_tables_at(heap); + env_[i] = (char *)heap; + memcpy((void *)heap, env[i], size); + heap += size; + } + env_[envc] = 0; + + memcpy(auxv_ptr, auxv, sizeof(Elf32_auxv) * (auxvc)); + + current_process->image.heap = heap; /* heap end */ + current_process->image.heap_actual = heap + (0x1000 - heap % 0x1000); + alloc_frame(get_page(current_process->image.heap_actual, 1, current_directory), 0, 1); + invalidate_tables_at(current_process->image.heap_actual); + current_process->image.user_stack = USER_STACK_TOP; + + current_process->image.start = entry; + + /* Close all fds >= 3 */ + for (unsigned int i = 3; i < current_process->fds->length; ++i) { + if (current_process->fds->entries[i]) { + close_fs(current_process->fds->entries[i]); + current_process->fds->entries[i] = NULL; + } + } + + /* Go go go */ + enter_user_jmp(entry, argc, argv_, USER_STACK_TOP); + + /* We should never reach this code */ + return -1; +} + +int exec_shebang(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp) { + /* Read MAX_LINE... */ + char tmp[100]; + read_fs(file, 0, 100, (unsigned char *)tmp); close_fs(file); + char * cmd = (char *)&tmp[2]; + char * space_or_linefeed = strpbrk(cmd, " \n"); + char * arg = NULL; + + if (!space_or_linefeed) { + debug_print(WARNING, "No space or linefeed found."); + return -ENOEXEC; + } + + if (*space_or_linefeed == ' ') { + /* Oh lovely, an argument */ + *space_or_linefeed = '\0'; + space_or_linefeed++; + arg = space_or_linefeed; + space_or_linefeed = strpbrk(space_or_linefeed, "\n"); + if (!space_or_linefeed) { + debug_print(WARNING, "Argument exceeded maximum length"); + return -ENOEXEC; + } + } + *space_or_linefeed = '\0'; + + char script[strlen(path)+1]; + memcpy(script, path, strlen(path)+1); + + unsigned int nargc = argc + (arg ? 2 : 1); + char * args[nargc + 1]; + args[0] = cmd; + args[1] = arg ? arg : script; + args[2] = arg ? script : NULL; + args[3] = NULL; + + int j = arg ? 3 : 2; + for (int i = 1; i < argc; ++i, ++j) { + args[j] = argv[i]; + } + args[j] = NULL; + + return exec(cmd, nargc, args, env); +} + +/* Consider exposing this and making it a list so it can be extended ... */ +typedef int (*exec_func)(char * path, fs_node_t * file, int argc, char ** argv, char ** env, int interp); +typedef struct { + exec_func func; + unsigned char bytes[4]; + unsigned int match; + char * name; +} exec_def_t; + +exec_def_t fmts[] = { + {exec_elf, {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3}, 4, "ELF"}, + {exec_shebang, {'#', '!', 0, 0}, 2, "#!"}, +}; + +static int matches(unsigned char * a, unsigned char * b, unsigned int len) { + for (unsigned int i = 0; i < len; ++i) { + if (a[i] != b[i]) return 0; + } + return 1; +} + +/** + * Load an execute a binary. + * + * This determines the binary type (eg., ELF binary, she-bang script, etc.) + * and then calls the appropriate underlying exec function. + * + * @param path Path to the executable to attempt to execute. + * @param argc Number of arguments (because I'm not counting for you) + * @param argv Pointer to a string of arguments + */ +int exec( + char * path, /* Path to the executable to run */ + int argc, /* Argument count (ie, /bin/echo hello world = 3) */ + char ** argv, /* Argument strings (including executable path) */ + char ** env /* Environmen variables */ + ) { + /* Open the file */ + fs_node_t * file = kopen(path,0); + if (!file) { + /* Command not found */ + return -ENOENT; + } + + /* Read four bytes of the file */ + unsigned char head[4]; + read_fs(file, 0, 4, head); + + debug_print(WARNING, "First four bytes: %c%c%c%c", head[0], head[1], head[2], head[3]); + + current_process->name = strdup(path); + gettimeofday((struct timeval *)¤t_process->start, NULL); + + for (unsigned int i = 0; i < sizeof(fmts) / sizeof(exec_def_t); ++i) { + if (matches(fmts[i].bytes, head, fmts[i].match)) { + debug_print(WARNING, "Matched executor: %s", fmts[i].name); + return fmts[i].func(path, file, argc, argv, env, 0); + } + } + + debug_print(WARNING, "Exec failed?"); + return -ENOEXEC; +} + + +int +system( + char * path, /* Path to the executable to run */ + int argc, /* Argument count (ie, /bin/echo hello world = 3) */ + char ** argv /* Argument strings (including executable path) */ + ) { + char ** argv_ = malloc(sizeof(char *) * (argc + 1)); + for (int j = 0; j < argc; ++j) { + argv_[j] = malloc((strlen(argv[j]) + 1) * sizeof(char)); + memcpy(argv_[j], argv[j], strlen(argv[j]) + 1); + } + argv_[argc] = 0; + char * env[] = {NULL}; + set_process_environment((process_t*)current_process, clone_directory(current_directory)); + current_directory = current_process->thread.page_directory; + switch_page_directory(current_directory); + + current_process->cmdline = argv_; + + exec(path,argc,argv_,env); + debug_print(ERROR, "Failed to execute process!"); + kexit(-1); + return -1; +} + diff --git a/kernel/misc/kprintf.c b/kernel/misc/kprintf.c new file mode 100644 index 00000000..25d5e92b --- /dev/null +++ b/kernel/misc/kprintf.c @@ -0,0 +1,158 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * + * Kernel printf implementation + * + * Simple, painfully lacking, implementation of printf(), + * for the kernel of all things. + */ +#include +#include +#include +#include + +/* + * Integer to string + */ +static void print_dec(unsigned int value, unsigned int width, char * buf, int * ptr ) { + unsigned int n_width = 1; + unsigned int i = 9; + while (value > i && i < UINT32_MAX) { + n_width += 1; + i *= 10; + i += 9; + } + + int printed = 0; + while (n_width + printed < width) { + buf[*ptr] = '0'; + *ptr += 1; + printed += 1; + } + + i = n_width; + while (i > 0) { + unsigned int n = value / 10; + int r = value % 10; + buf[*ptr + i - 1] = r + '0'; + i--; + value = n; + } + *ptr += n_width; +} + +/* + * Hexadecimal to string + */ +static void print_hex(unsigned int value, unsigned int width, char * buf, int * ptr) { + int i = width; + + if (i == 0) i = 8; + + unsigned int n_width = 1; + unsigned int j = 0x0F; + while (value > j && j < UINT32_MAX) { + n_width += 1; + j *= 0x10; + j += 0x0F; + } + + while (i > (int)n_width) { + buf[*ptr] = '0'; + *ptr += 1; + i--; + } + + i = (int)n_width; + while (i-- > 0) { + buf[*ptr] = "0123456789abcdef"[(value>>(i*4))&0xF]; + *ptr += + 1; + } +} + +/* + * vasprintf() + */ +size_t vasprintf(char * buf, const char * fmt, va_list args) { + int i = 0; + char * s; + char * b = buf; + for (const char *f = fmt; *f; f++) { + if (*f != '%') { + *b++ = *f; + continue; + } + ++f; + unsigned int arg_width = 0; + while (*f >= '0' && *f <= '9') { + arg_width *= 10; + arg_width += *f - '0'; + ++f; + } + /* fmt[i] == '%' */ + switch (*f) { + case 's': /* String pointer -> String */ + s = (char *)va_arg(args, char *); + if (s == NULL) { + s = "(null)"; + } + while (*s) { + *b++ = *s++; + } + break; + case 'c': /* Single character */ + *b++ = (char)va_arg(args, int); + break; + case 'x': /* Hexadecimal number */ + i = b - buf; + print_hex((unsigned long)va_arg(args, unsigned long), arg_width, buf, &i); + b = buf + i; + break; + case 'd': /* Decimal number */ + i = b - buf; + print_dec((unsigned long)va_arg(args, unsigned long), arg_width, buf, &i); + b = buf + i; + break; + case '%': /* Escape */ + *b++ = '%'; + break; + default: /* Nothing at all, just dump it */ + *b++ = *f; + break; + } + } + /* Ensure the buffer ends in a null */ + *b = '\0'; + return b - buf; + +} + +static unsigned short * textmemptr = (unsigned short *)0xB8000; +static void placech(unsigned char c, int x, int y, int attr) { + unsigned short *where; + unsigned att = attr << 8; + where = textmemptr + (y * 80 + x); + *where = c | att; +} + +int fprintf(fs_node_t * device, char *fmt, ...) { + va_list args; + va_start(args, fmt); + char buffer[1024]; + vasprintf(buffer, fmt, args); + va_end(args); + + return write_fs(device, 0, strlen(buffer), (uint8_t *)buffer); +} + + +int sprintf(char * buf, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int out = vasprintf(buf, fmt, args); + va_end(args); + return out; +} + diff --git a/kernel/misc/logging.c b/kernel/misc/logging.c new file mode 100644 index 00000000..7ea24068 --- /dev/null +++ b/kernel/misc/logging.c @@ -0,0 +1,53 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * + * Kernel Logging Facility + * + * Maintains a log in-memory as well as to serial (unless + * told not to). + */ + +#include +#include +#include +#include +#include + +log_type_t debug_level = NOTICE; +void * debug_file = NULL; +void (*debug_hook)(void *, char *) = NULL; +void (*debug_video_crash)(char **) = NULL; + +static char * c_messages[] = { + " \033[1;34mINFO\033[0m:", + " \033[1;35mNOTICE\033[0m:", + " \033[1;33mWARNING\033[0m:", + " \033[1;31mERROR\033[0m:", + " \033[1;37;41mCRITICAL\033[0m:", + " \033[1;31;44mINSANE\033[0m:" +}; + +static char buffer[1024]; + +void _debug_print(char * title, int line_no, log_type_t level, char *fmt, ...) { + if (level >= debug_level && debug_file) { + va_list args; + va_start(args, fmt); + vasprintf(buffer, fmt, args); + va_end(args); + + char * type; + if (level > INSANE) { + type = ""; + } else { + type = c_messages[level]; + } + + fprintf(debug_file, "[%10d.%3d:%s:%d]%s %s\n", timer_ticks, timer_subticks, title, line_no, type, buffer); + + } + /* else ignore */ +} + diff --git a/kernel/misc/multiboot.c b/kernel/misc/multiboot.c new file mode 100644 index 00000000..1a3770a5 --- /dev/null +++ b/kernel/misc/multiboot.c @@ -0,0 +1,76 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * + * Multiboot (GRUB) handler + */ +#include +#include +#include + +char * ramdisk = NULL; +struct multiboot * mboot_ptr = NULL; + +struct multiboot * +copy_multiboot( + struct multiboot *mboot_ptr + ) { + struct multiboot *new_header = (struct multiboot *)kmalloc(sizeof(struct multiboot)); + memcpy(new_header, mboot_ptr, sizeof(struct multiboot)); + return new_header; +} + +void +dump_multiboot( + struct multiboot *mboot_ptr + ) { + debug_print(INFO, "MULTIBOOT header at 0x%x:", (uintptr_t)mboot_ptr); + debug_print(INFO, "Flags : 0x%x", mboot_ptr->flags); + debug_print(INFO, "Mem Lo: 0x%x", mboot_ptr->mem_lower); + debug_print(INFO, "Mem Hi: 0x%x", mboot_ptr->mem_upper); + debug_print(INFO, "Boot d: 0x%x", mboot_ptr->boot_device); + debug_print(INFO, "cmdlin: 0x%x", mboot_ptr->cmdline); + debug_print(INFO, "Mods : 0x%x", mboot_ptr->mods_count); + debug_print(INFO, "Addr : 0x%x", mboot_ptr->mods_addr); + debug_print(INFO, "ELF n : 0x%x", mboot_ptr->num); + debug_print(INFO, "ELF s : 0x%x", mboot_ptr->size); + debug_print(INFO, "ELF a : 0x%x", mboot_ptr->addr); + debug_print(INFO, "ELF h : 0x%x", mboot_ptr->shndx); + debug_print(INFO, "MMap : 0x%x", mboot_ptr->mmap_length); + debug_print(INFO, "Addr : 0x%x", mboot_ptr->mmap_addr); + debug_print(INFO, "Drives: 0x%x", mboot_ptr->drives_length); + debug_print(INFO, "Addr : 0x%x", mboot_ptr->drives_addr); + debug_print(INFO, "Config: 0x%x", mboot_ptr->config_table); + debug_print(INFO, "Loader: 0x%x", mboot_ptr->boot_loader_name); + debug_print(INFO, "APM : 0x%x", mboot_ptr->apm_table); + debug_print(INFO, "VBE Co: 0x%x", mboot_ptr->vbe_control_info); + debug_print(INFO, "VBE Mo: 0x%x", mboot_ptr->vbe_mode_info); + debug_print(INFO, "VBE In: 0x%x", mboot_ptr->vbe_mode); + debug_print(INFO, "VBE se: 0x%x", mboot_ptr->vbe_interface_seg); + debug_print(INFO, "VBE of: 0x%x", mboot_ptr->vbe_interface_off); + debug_print(INFO, "VBE le: 0x%x", mboot_ptr->vbe_interface_len); + if (mboot_ptr->flags & (1 << 2)) { + debug_print(INFO, "Started with: %s", (char *)mboot_ptr->cmdline); + } + if (mboot_ptr->flags & (1 << 9)) { + debug_print(INFO, "Booted from: %s", (char *)mboot_ptr->boot_loader_name); + } + if (mboot_ptr->flags & (1 << 0)) { + debug_print(INFO, "%dkB lower memory", mboot_ptr->mem_lower); + int mem_mb = mboot_ptr->mem_upper / 1024; + debug_print(INFO, "%dkB higher memory (%dMB)", mboot_ptr->mem_upper, mem_mb); + } + if (mboot_ptr->flags & (1 << 3)) { + debug_print(INFO, "Found %d module(s).", mboot_ptr->mods_count); + if (mboot_ptr->mods_count > 0) { + uint32_t i; + for (i = 0; i < mboot_ptr->mods_count; ++i ) { + uint32_t module_start = *((uint32_t*)mboot_ptr->mods_addr + 8 * i); + uint32_t module_end = *(uint32_t*)(mboot_ptr->mods_addr + 8 * i + 4); + debug_print(INFO, "Module %d is at 0x%x:0x%x", i+1, module_start, module_end); + } + } + } +} + diff --git a/kernel/misc/tokenize.c b/kernel/misc/tokenize.c new file mode 100644 index 00000000..1861197a --- /dev/null +++ b/kernel/misc/tokenize.c @@ -0,0 +1,23 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2013 Kevin Lange + */ +#include +#include +#include + +int tokenize(char * str, char * sep, char **buf) { + char * pch_i; + char * save_i; + int argc = 0; + pch_i = strtok_r(str,sep,&save_i); + if (!pch_i) { return 0; } + while (pch_i != NULL) { + buf[argc] = (char *)pch_i; + ++argc; + pch_i = strtok_r(NULL,sep,&save_i); + } + buf[argc] = NULL; + return argc; +} diff --git a/kernel/misc/ubsan.c b/kernel/misc/ubsan.c new file mode 100644 index 00000000..be8c9a08 --- /dev/null +++ b/kernel/misc/ubsan.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include + +#define EARLY_LOG_DEVICE 0x3F8 +static uint32_t _ubsan_log_write(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + for (unsigned int i = 0; i < size; ++i) { + outportb(EARLY_LOG_DEVICE, buffer[i]); + } + return size; +} +static fs_node_t _ubsan_log = { .write = &_ubsan_log_write }; + +void ubsan_debug(struct SourceLocation * location) { + fprintf(&_ubsan_log, "[ubsan] %s:%d:%dc - ", location->file_name, location->line, location->column); +} + +void __ubsan_handle_add_overflow(struct OverflowData * data, unsigned long lhs, unsigned long rhs) { + ubsan_debug(&data->location); + fprintf(&_ubsan_log, "Overflow in add: %d %d\n", lhs, rhs); +} + +void __ubsan_handle_sub_overflow(struct OverflowData * data, unsigned long lhs, unsigned long rhs) { + ubsan_debug(&data->location); + fprintf(&_ubsan_log, "Overflow in sub: %d %d\n", lhs, rhs); +} + +void __ubsan_handle_mul_overflow(struct OverflowData * data, unsigned long lhs, unsigned long rhs) { + fprintf(&_ubsan_log, "Overflow in mul: %d %d\n", lhs, rhs); +} + +void __ubsan_handle_divrem_overflow(struct OverflowData * data, unsigned long lhs, unsigned long rhs) { + ubsan_debug(&data->location); + fprintf(&_ubsan_log, "Overflow in divrem: %d %d\n", lhs, rhs); +} + +void __ubsan_handle_negate_overflow(struct OverflowData * data, unsigned long old) { + ubsan_debug(&data->location); + fprintf(&_ubsan_log, "Overflow in negate: %d\n", old); +} + +void __ubsan_handle_builtin_unreachable(struct UnreachableData * data) { + ubsan_debug(&data->location); + fprintf(&_ubsan_log, "called __builtin_unreachable()\n"); +} + +void __ubsan_handle_out_of_bounds(struct OutOfBoundsData * data, unsigned long index) { + ubsan_debug(&data->location); + fprintf(&_ubsan_log, "out of bounds array reference at %s[%d]\n", data->array_type->type_name, index); +} + +void __ubsan_handle_shift_out_of_bounds(struct ShiftOutOfBoundsData * data, unsigned long lhs, unsigned long rhs) { + ubsan_debug(&data->location); + fprintf(&_ubsan_log, "shift is out of bounds: %d %d\n", lhs, rhs); +} + +#define IS_ALIGNED(a, b) (((a) & ((__typeof__(a))(b)-1)) == 0) + +void __ubsan_handle_type_mismatch(struct TypeMismatchData * data, unsigned long ptr) { + return; + ubsan_debug(&data->location); + if (data->alignment && !IS_ALIGNED(ptr, data->alignment)) { + fprintf(&_ubsan_log, "bad alignment in read at 0x%x (wanted %d)\n", ptr, data->alignment); + } else { + fprintf(&_ubsan_log, "type mismatch in reference at 0x%x\n", ptr); + } +} + +void __ubsan_handle_vla_bound_not_positive(struct VLABoundData * data, unsigned long bound) { + ubsan_debug(&data->location); + fprintf(&_ubsan_log, "vla bound not positive: %d\n", bound); +} + diff --git a/kernel/spin.c b/kernel/spin.c new file mode 100644 index 00000000..456ac2ad --- /dev/null +++ b/kernel/spin.c @@ -0,0 +1,57 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015 Dale Weiler + * + * Spin locks with waiters + * + */ +#include + +static inline int arch_atomic_swap(volatile int * x, int v) { + asm("xchg %0, %1" : "=r"(v), "=m"(*x) : "0"(v) : "memory"); + return v; +} + +static inline void arch_atomic_store(volatile int * p, int x) { + asm("movl %1, %0" : "=m"(*p) : "r"(x) : "memory"); +} + +static inline void arch_atomic_inc(volatile int * x) { + asm("lock; incl %0" : "=m"(*x) : "m"(*x) : "memory"); +} + +static inline void arch_atomic_dec(volatile int * x) { + asm("lock; decl %0" : "=m"(*x) : "m"(*x) : "memory"); +} + +void spin_wait(volatile int * addr, volatile int * waiters) { + if (waiters) { + arch_atomic_inc(waiters); + } + while (*addr) { + switch_task(1); + } + if (waiters) { + arch_atomic_dec(waiters); + } +} + +void spin_lock(spin_lock_t lock) { + while (arch_atomic_swap(lock, 1)) { + spin_wait(lock, lock+1); + } +} + +void spin_init(spin_lock_t lock) { + lock[0] = 0; + lock[1] = 0; +} + +void spin_unlock(spin_lock_t lock) { + if (lock[0]) { + arch_atomic_store(lock, 0); + if (lock[1]) + switch_task(1); + } +} diff --git a/kernel/symbols.S b/kernel/symbols.S new file mode 100644 index 00000000..5be57f28 --- /dev/null +++ b/kernel/symbols.S @@ -0,0 +1,2791 @@ +.section .symbols + +.extern alloc_frame +.type alloc_frame, @function + +.extern args_parse +.type args_parse, @function + +.extern args_present +.type args_present, @function + +.extern args_value +.type args_value, @function + +.extern assert_failed +.type assert_failed, @function + +.extern atoi +.type atoi, @function + +.extern bitset_clear +.type bitset_clear, @function + +.extern bitset_ffub +.type bitset_ffub, @function + +.extern bitset_free +.type bitset_free, @function + +.extern bitset_init +.type bitset_init, @function + +.extern bitset_set +.type bitset_set, @function + +.extern bitset_test +.type bitset_test, @function + +.extern boot_arg +.type boot_arg, @function + +.extern boot_arg_extra +.type boot_arg_extra, @function + +.extern boot_time +.type boot_time, @function + +.extern bss +.type bss, @function + +.extern calloc +.type calloc, @function + +.extern canonicalize_path +.type canonicalize_path, @function + +.extern chmod_fs +.type chmod_fs, @function + +.extern chown_fs +.type chown_fs, @function + +.extern cleanup_process +.type cleanup_process, @function + +.extern clear_frame +.type clear_frame, @function + +.extern clone +.type clone, @function + +.extern clone_directory +.type clone_directory, @function + +.extern clone_fs +.type clone_fs, @function + +.extern clone_table +.type clone_table, @function + +.extern close_fs +.type close_fs, @function + +.extern close_pipe +.type close_pipe, @function + +.extern close_pty_master +.type close_pty_master, @function + +.extern close_pty_slave +.type close_pty_slave, @function + +.extern cmdline +.type cmdline, @function + +.extern cmos_dump +.type cmos_dump, @function + +.extern code +.type code, @function + +.extern copy_multiboot +.type copy_multiboot, @function + +.extern copy_page_physical +.type copy_page_physical, @function + +.extern create_file_fs +.type create_file_fs, @function + +.extern create_kernel_tasklet +.type create_kernel_tasklet, @function + +.extern current_directory +.type current_directory, @function + +.extern current_process +.type current_process, @function + +.extern data +.type data, @function + +.extern debug_file +.type debug_file, @function + +.extern debug_hook +.type debug_hook, @function + +.extern debug_level +.type debug_level, @function + +.extern _debug_print +.type _debug_print, @function + +.extern debug_print_directory +.type debug_print_directory, @function + +.extern debug_print_process_tree +.type debug_print_process_tree, @function + +.extern debug_print_process_tree_node +.type debug_print_process_tree_node, @function + +.extern debug_print_vfs_tree +.type debug_print_vfs_tree, @function + +.extern debug_print_vfs_tree_node +.type debug_print_vfs_tree_node, @function + +.extern debug_video_crash +.type debug_video_crash, @function + +.extern default_name +.type default_name, @function + +.extern delete_process +.type delete_process, @function + +.extern disable_fpu +.type disable_fpu, @function + +.extern dma_frame +.type dma_frame, @function + +.extern dump_multiboot +.type dump_multiboot, @function + +.extern enable_fpu +.type enable_fpu, @function + +.extern end +.type end, @function + +.extern enter_signal_handler +.type enter_signal_handler, @function + +.extern enter_user_jmp +.type enter_user_jmp, @function + +.extern enter_userspace +.type enter_userspace, @function + +.extern exec +.type exec, @function + +.extern exec_elf +.type exec_elf, @function + +.extern exec_shebang +.type exec_shebang, @function + +.extern fault_handler +.type fault_handler, @function + +.extern finddir_fs +.type finddir_fs, @function + +.extern first_frame +.type first_frame, @function + +.extern first_n_frames +.type first_n_frames, @function + +.extern fix_signal_stacks +.type fix_signal_stacks, @function + +.extern fmts +.type fmts, @function + +.extern fork +.type fork, @function + +.extern fprintf +.type fprintf, @function + +.extern fpu_install +.type fpu_install, @function + +.extern fpu_thread +.type fpu_thread, @function + +.extern frames +.type frames, @function + +.extern free +.type free, @function + +.extern free_frame +.type free_frame, @function + +.extern frozen_stack +.type frozen_stack, @function + +.extern fs_root +.type fs_root, @function + +.extern fs_tree +.type fs_tree, @function + +.extern fs_types +.type fs_types, @function + +.extern gdt_flush +.type gdt_flush, @function + +.extern gdt_install +.type gdt_install, @function + +.extern gdt_set_gate +.type gdt_set_gate, @function + +.extern get_date +.type get_date, @function + +.extern get_mount_point +.type get_mount_point, @function + +.extern get_next_pid +.type get_next_pid, @function + +.extern get_page +.type get_page, @function + +.extern getpid +.type getpid, @function + +.extern get_time +.type get_time, @function + +.extern gettimeofday +.type gettimeofday, @function + +.extern halt_and_catch_fire +.type halt_and_catch_fire, @function + +.extern handle_signal +.type handle_signal, @function + +.extern hashmap_create +.type hashmap_create, @function + +.extern hashmap_create_int +.type hashmap_create_int, @function + +.extern hashmap_free +.type hashmap_free, @function + +.extern hashmap_get +.type hashmap_get, @function + +.extern hashmap_has +.type hashmap_has, @function + +.extern hashmap_int_comp +.type hashmap_int_comp, @function + +.extern hashmap_int_dupe +.type hashmap_int_dupe, @function + +.extern hashmap_int_hash +.type hashmap_int_hash, @function + +.extern hashmap_keys +.type hashmap_keys, @function + +.extern hashmap_remove +.type hashmap_remove, @function + +.extern hashmap_set +.type hashmap_set, @function + +.extern hashmap_string_comp +.type hashmap_string_comp, @function + +.extern hashmap_string_dupe +.type hashmap_string_dupe, @function + +.extern hashmap_string_hash +.type hashmap_string_hash, @function + +.extern hashmap_values +.type hashmap_values, @function + +.extern has_permission +.type has_permission, @function + +.extern heap_end +.type heap_end, @function + +.extern heap_install +.type heap_install, @function + +.extern idt_install +.type idt_install, @function + +.extern idt_load +.type idt_load, @function + +.extern idt_set_gate +.type idt_set_gate, @function + +.extern init_fpu +.type init_fpu, @function + +.extern initial_esp +.type initial_esp, @function + +.extern initialize_process_tree +.type initialize_process_tree, @function + +.extern inportb +.type inportb, @function + +.extern inportl +.type inportl, @function + +.extern inports +.type inports, @function + +.extern inportsm +.type inportsm, @function + +.extern int_disable +.type int_disable, @function + +.extern int_enable +.type int_enable, @function + +.extern int_resume +.type int_resume, @function + +.extern invalidate_page_tables +.type invalidate_page_tables, @function + +.extern invalidate_tables_at +.type invalidate_tables_at, @function + +.extern invalid_op +.type invalid_op, @function + +.extern ioctl_fs +.type ioctl_fs, @function + +.extern ioctl_pty_master +.type ioctl_pty_master, @function + +.extern ioctl_pty_slave +.type ioctl_pty_slave, @function + +.extern _irq0 +.type _irq0, @function + +.extern _irq1 +.type _irq1, @function + +.extern _irq10 +.type _irq10, @function + +.extern _irq11 +.type _irq11, @function + +.extern _irq12 +.type _irq12, @function + +.extern _irq13 +.type _irq13, @function + +.extern _irq14 +.type _irq14, @function + +.extern _irq15 +.type _irq15, @function + +.extern _irq2 +.type _irq2, @function + +.extern _irq3 +.type _irq3, @function + +.extern _irq4 +.type _irq4, @function + +.extern _irq5 +.type _irq5, @function + +.extern _irq6 +.type _irq6, @function + +.extern _irq7 +.type _irq7, @function + +.extern _irq8 +.type _irq8, @function + +.extern _irq9 +.type _irq9, @function + +.extern irq_ack +.type irq_ack, @function + +.extern irq_handler +.type irq_handler, @function + +.extern irq_install +.type irq_install, @function + +.extern irq_install_handler +.type irq_install_handler, @function + +.extern irq_uninstall_handler +.type irq_uninstall_handler, @function + +.extern isdeadly +.type isdeadly, @function + +.extern _isr0 +.type _isr0, @function + +.extern _isr1 +.type _isr1, @function + +.extern _isr10 +.type _isr10, @function + +.extern _isr11 +.type _isr11, @function + +.extern _isr12 +.type _isr12, @function + +.extern _isr127 +.type _isr127, @function + +.extern _isr13 +.type _isr13, @function + +.extern _isr14 +.type _isr14, @function + +.extern _isr15 +.type _isr15, @function + +.extern _isr16 +.type _isr16, @function + +.extern _isr17 +.type _isr17, @function + +.extern _isr18 +.type _isr18, @function + +.extern _isr19 +.type _isr19, @function + +.extern _isr2 +.type _isr2, @function + +.extern _isr20 +.type _isr20, @function + +.extern _isr21 +.type _isr21, @function + +.extern _isr22 +.type _isr22, @function + +.extern _isr23 +.type _isr23, @function + +.extern _isr24 +.type _isr24, @function + +.extern _isr25 +.type _isr25, @function + +.extern _isr26 +.type _isr26, @function + +.extern _isr27 +.type _isr27, @function + +.extern _isr28 +.type _isr28, @function + +.extern _isr29 +.type _isr29, @function + +.extern _isr3 +.type _isr3, @function + +.extern _isr30 +.type _isr30, @function + +.extern _isr31 +.type _isr31, @function + +.extern _isr4 +.type _isr4, @function + +.extern _isr5 +.type _isr5, @function + +.extern _isr6 +.type _isr6, @function + +.extern _isr7 +.type _isr7, @function + +.extern _isr8 +.type _isr8, @function + +.extern _isr9 +.type _isr9, @function + +.extern isrs_install +.type isrs_install, @function + +.extern isrs_install_handler +.type isrs_install_handler, @function + +.extern isrs_uninstall_handler +.type isrs_uninstall_handler, @function + +.extern is_update_in_progress +.type is_update_in_progress, @function + +.extern is_valid_process +.type is_valid_process, @function + +.extern __kernel_arch +.type __kernel_arch, @function + +.extern kernel_args_map +.type kernel_args_map, @function + +.extern __kernel_build_date +.type __kernel_build_date, @function + +.extern __kernel_build_time +.type __kernel_build_time, @function + +.extern __kernel_compiler_version +.type __kernel_compiler_version, @function + +.extern kernel_directory +.type kernel_directory, @function + +.extern kernel_heap_alloc_point +.type kernel_heap_alloc_point, @function + +.extern kernel_idle_task +.type kernel_idle_task, @function + +.extern __kernel_name +.type __kernel_name, @function + +.extern kernel_symbols_end +.type kernel_symbols_end, @function + +.extern kernel_symbols_start +.type kernel_symbols_start, @function + +.extern __kernel_version_codename +.type __kernel_version_codename, @function + +.extern __kernel_version_format +.type __kernel_version_format, @function + +.extern __kernel_version_lower +.type __kernel_version_lower, @function + +.extern __kernel_version_major +.type __kernel_version_major, @function + +.extern __kernel_version_minor +.type __kernel_version_minor, @function + +.extern __kernel_version_suffix +.type __kernel_version_suffix, @function + +.extern kexit +.type kexit, @function + +.extern kmain +.type kmain, @function + +.extern kmalloc +.type kmalloc, @function + +.extern kmalloc_p +.type kmalloc_p, @function + +.extern kmalloc_real +.type kmalloc_real, @function + +.extern kmalloc_startat +.type kmalloc_startat, @function + +.extern kopen +.type kopen, @function + +.extern kopen_recur +.type kopen_recur, @function + +.extern krand +.type krand, @function + +.extern kvmalloc +.type kvmalloc, @function + +.extern kvmalloc_p +.type kvmalloc_p, @function + +.extern lfind +.type lfind, @function + +.extern list_append +.type list_append, @function + +.extern list_append_after +.type list_append_after, @function + +.extern list_append_before +.type list_append_before, @function + +.extern list_copy +.type list_copy, @function + +.extern list_create +.type list_create, @function + +.extern list_delete +.type list_delete, @function + +.extern list_dequeue +.type list_dequeue, @function + +.extern list_destroy +.type list_destroy, @function + +.extern list_find +.type list_find, @function + +.extern list_free +.type list_free, @function + +.extern list_index_of +.type list_index_of, @function + +.extern list_insert +.type list_insert, @function + +.extern list_insert_after +.type list_insert_after, @function + +.extern list_insert_before +.type list_insert_before, @function + +.extern list_merge +.type list_merge, @function + +.extern list_pop +.type list_pop, @function + +.extern list_remove +.type list_remove, @function + +.extern make_pipe +.type make_pipe, @function + +.extern make_process_ready +.type make_process_ready, @function + +.extern make_unix_pipe +.type make_unix_pipe, @function + +.extern malloc +.type malloc, @function + +.extern map_to_physical +.type map_to_physical, @function + +.extern map_vfs_directory +.type map_vfs_directory, @function + +.extern mboot_ptr +.type mboot_ptr, @function + +.extern memchr +.type memchr, @function + +.extern memcmp +.type memcmp, @function + +.extern memcpy +.type memcpy, @function + +.extern memmove +.type memmove, @function + +.extern memory_total +.type memory_total, @function + +.extern memory_use +.type memory_use, @function + +.extern memrchr +.type memrchr, @function + +.extern memset +.type memset, @function + +.extern memsetw +.type memsetw, @function + +.extern mkdir_fs +.type mkdir_fs, @function + +.extern module_load +.type module_load, @function + +.extern module_load_direct +.type module_load_direct, @function + +.extern module_quickcheck +.type module_quickcheck, @function + +.extern modules_get_list +.type modules_get_list, @function + +.extern modules_get_symbols +.type modules_get_symbols, @function + +.extern modules_install +.type modules_install, @function + +.extern module_unload +.type module_unload, @function + +.extern next_pid +.type next_pid, @function + +.extern next_ready_process +.type next_ready_process, @function + +.extern nframes +.type nframes, @function + +.extern now +.type now, @function + +.extern num_syscalls +.type num_syscalls, @function + +.extern open_fs +.type open_fs, @function + +.extern open_pipe +.type open_pipe, @function + +.extern open_pty_master +.type open_pty_master, @function + +.extern open_pty_slave +.type open_pty_slave, @function + +.extern outportb +.type outportb, @function + +.extern outportl +.type outportl, @function + +.extern outports +.type outports, @function + +.extern outportsm +.type outportsm, @function + +.extern page_fault +.type page_fault, @function + +.extern paging_finalize +.type paging_finalize, @function + +.extern paging_install +.type paging_install, @function + +.extern paging_mark_system +.type paging_mark_system, @function + +.extern PciClassCodeTable +.type PciClassCodeTable, @function + +.extern PciCommandFlags +.type PciCommandFlags, @function + +.extern pci_device_lookup +.type pci_device_lookup, @function + +.extern PciDevSelFlags +.type PciDevSelFlags, @function + +.extern PciDevTable +.type PciDevTable, @function + +.extern pci_find_type +.type pci_find_type, @function + +.extern pci_read_field +.type pci_read_field, @function + +.extern pci_scan +.type pci_scan, @function + +.extern pci_scan_bus +.type pci_scan_bus, @function + +.extern pci_scan_func +.type pci_scan_func, @function + +.extern pci_scan_hit +.type pci_scan_hit, @function + +.extern pci_scan_slot +.type pci_scan_slot, @function + +.extern PciStatusFlags +.type PciStatusFlags, @function + +.extern pci_vendor_lookup +.type pci_vendor_lookup, @function + +.extern PciVenTable +.type PciVenTable, @function + +.extern pci_write_field +.type pci_write_field, @function + +.extern phys +.type phys, @function + +.extern pipe_size +.type pipe_size, @function + +.extern pipe_unsize +.type pipe_unsize, @function + +.extern placement_pointer +.type placement_pointer, @function + +.extern probable_function_name +.type probable_function_name, @function + +.extern process_alert_node +.type process_alert_node, @function + +.extern process_append_fd +.type process_append_fd, @function + +.extern process_available +.type process_available, @function + +.extern process_awaken_from_fswait +.type process_awaken_from_fswait, @function + +.extern process_compare +.type process_compare, @function + +.extern process_disown +.type process_disown, @function + +.extern process_from_pid +.type process_from_pid, @function + +.extern process_get_parent +.type process_get_parent, @function + +.extern process_is_ready +.type process_is_ready, @function + +.extern process_list +.type process_list, @function + +.extern process_move_fd +.type process_move_fd, @function + +.extern process_queue +.type process_queue, @function + +.extern process_tree +.type process_tree, @function + +.extern process_wait +.type process_wait, @function + +.extern process_wait_nodes +.type process_wait_nodes, @function + +.extern process_wake +.type process_wake, @function + +.extern pty_available_input +.type pty_available_input, @function + +.extern pty_available_output +.type pty_available_output, @function + +.extern pty_create +.type pty_create, @function + +.extern pty_install +.type pty_install, @function + +.extern pty_ioctl +.type pty_ioctl, @function + +.extern pty_list +.type pty_list, @function + +.extern pty_master_create +.type pty_master_create, @function + +.extern pty_new +.type pty_new, @function + +.extern pty_slave_create +.type pty_slave_create, @function + +.extern ramdisk +.type ramdisk, @function + +.extern ramdisk_mount +.type ramdisk_mount, @function + +.extern read_cmos +.type read_cmos, @function + +.extern readdir_fs +.type readdir_fs, @function + +.extern read_eip +.type read_eip, @function + +.extern read_fs +.type read_fs, @function + +.extern readlink_fs +.type readlink_fs, @function + +.extern read_pipe +.type read_pipe, @function + +.extern read_pty_master +.type read_pty_master, @function + +.extern read_pty_slave +.type read_pty_slave, @function + +.extern realloc +.type realloc, @function + +.extern reap_process +.type reap_process, @function + +.extern relative_time +.type relative_time, @function + +.extern release_directory +.type release_directory, @function + +.extern release_directory_for_exec +.type release_directory_for_exec, @function + +.extern restore_fpu +.type restore_fpu, @function + +.extern rets_from_sig +.type rets_from_sig, @function + +.extern return_from_signal_handler +.type return_from_signal_handler, @function + +.extern return_to_userspace +.type return_to_userspace, @function + +.extern rfind +.type rfind, @function + +.extern ring_buffer_available +.type ring_buffer_available, @function + +.extern ring_buffer_create +.type ring_buffer_create, @function + +.extern ring_buffer_destroy +.type ring_buffer_destroy, @function + +.extern ring_buffer_interrupt +.type ring_buffer_interrupt, @function + +.extern ring_buffer_read +.type ring_buffer_read, @function + +.extern ring_buffer_select_wait +.type ring_buffer_select_wait, @function + +.extern ring_buffer_size +.type ring_buffer_size, @function + +.extern ring_buffer_unread +.type ring_buffer_unread, @function + +.extern ring_buffer_write +.type ring_buffer_write, @function + +.extern save_fpu +.type save_fpu, @function + +.extern saves +.type saves, @function + +.extern sbrk +.type sbrk, @function + +.extern secs_of_month +.type secs_of_month, @function + +.extern secs_of_years +.type secs_of_years, @function + +.extern selectcheck_fs +.type selectcheck_fs, @function + +.extern selectwait_fs +.type selectwait_fs, @function + +.extern send_signal +.type send_signal, @function + +.extern set_fpu_cw +.type set_fpu_cw, @function + +.extern set_frame +.type set_frame, @function + +.extern set_kernel_stack +.type set_kernel_stack, @function + +.extern set_process_environment +.type set_process_environment, @function + +.extern shm_install +.type shm_install, @function + +.extern shm_obtain +.type shm_obtain, @function + +.extern shm_release +.type shm_release, @function + +.extern shm_release_all +.type shm_release_all, @function + +.extern shm_tree +.type shm_tree, @function + +.extern sleep_on +.type sleep_on, @function + +.extern sleep_queue +.type sleep_queue, @function + +.extern sleep_until +.type sleep_until, @function + +.extern spawn_init +.type spawn_init, @function + +.extern spawn_kidle +.type spawn_kidle, @function + +.extern spawn_process +.type spawn_process, @function + +.extern spin_init +.type spin_init, @function + +.extern spin_lock +.type spin_lock, @function + +.extern spin_unlock +.type spin_unlock, @function + +.extern spin_wait +.type spin_wait, @function + +.extern sprintf +.type sprintf, @function + +.extern start +.type start, @function + +.extern startswith +.type startswith, @function + +.extern stpcpy +.type stpcpy, @function + +.extern strchr +.type strchr, @function + +.extern strchrnul +.type strchrnul, @function + +.extern strcmp +.type strcmp, @function + +.extern strcpy +.type strcpy, @function + +.extern strcspn +.type strcspn, @function + +.extern strdup +.type strdup, @function + +.extern strlen +.type strlen, @function + +.extern strpbrk +.type strpbrk, @function + +.extern strrchr +.type strrchr, @function + +.extern strspn +.type strspn, @function + +.extern strstr +.type strstr, @function + +.extern strtok_r +.type strtok_r, @function + +.extern switch_fpu +.type switch_fpu, @function + +.extern switch_next +.type switch_next, @function + +.extern switch_page_directory +.type switch_page_directory, @function + +.extern switch_task +.type switch_task, @function + +.extern symbol_find +.type symbol_find, @function + +.extern symlink_fs +.type symlink_fs, @function + +.extern syscall_handler +.type syscall_handler, @function + +.extern syscalls_install +.type syscalls_install, @function + +.extern system +.type system, @function + +.extern task_exit +.type task_exit, @function + +.extern tasking_install +.type tasking_install, @function + +.extern test_frame +.type test_frame, @function + +.extern _timer_drift +.type _timer_drift, @function + +.extern timer_drift +.type timer_drift, @function + +.extern timer_handler +.type timer_handler, @function + +.extern timer_install +.type timer_install, @function + +.extern timer_phase +.type timer_phase, @function + +.extern timer_subticks +.type timer_subticks, @function + +.extern timer_ticks +.type timer_ticks, @function + +.extern tokenize +.type tokenize, @function + +.extern trace_pid +.type trace_pid, @function + +.extern tree_break_off +.type tree_break_off, @function + +.extern tree_count_children +.type tree_count_children, @function + +.extern tree_create +.type tree_create, @function + +.extern tree_destroy +.type tree_destroy, @function + +.extern tree_find +.type tree_find, @function + +.extern tree_find_parent +.type tree_find_parent, @function + +.extern tree_free +.type tree_free, @function + +.extern tree_node_create +.type tree_node_create, @function + +.extern tree_node_destroy +.type tree_node_destroy, @function + +.extern tree_node_find +.type tree_node_find, @function + +.extern tree_node_find_parent +.type tree_node_find_parent, @function + +.extern tree_node_free +.type tree_node_free, @function + +.extern tree_node_insert_child +.type tree_node_insert_child, @function + +.extern tree_node_insert_child_node +.type tree_node_insert_child_node, @function + +.extern tree_node_parent_remove +.type tree_node_parent_remove, @function + +.extern tree_node_remove +.type tree_node_remove, @function + +.extern tree_remove +.type tree_remove, @function + +.extern tree_remove_reparent_root +.type tree_remove_reparent_root, @function + +.extern tree_set_root +.type tree_set_root, @function + +.extern tss_flush +.type tss_flush, @function + +.extern ubsan_debug +.type ubsan_debug, @function + +.extern __ubsan_handle_add_overflow +.type __ubsan_handle_add_overflow, @function + +.extern __ubsan_handle_builtin_unreachable +.type __ubsan_handle_builtin_unreachable, @function + +.extern __ubsan_handle_divrem_overflow +.type __ubsan_handle_divrem_overflow, @function + +.extern __ubsan_handle_mul_overflow +.type __ubsan_handle_mul_overflow, @function + +.extern __ubsan_handle_negate_overflow +.type __ubsan_handle_negate_overflow, @function + +.extern __ubsan_handle_out_of_bounds +.type __ubsan_handle_out_of_bounds, @function + +.extern __ubsan_handle_shift_out_of_bounds +.type __ubsan_handle_shift_out_of_bounds, @function + +.extern __ubsan_handle_sub_overflow +.type __ubsan_handle_sub_overflow, @function + +.extern __ubsan_handle_type_mismatch +.type __ubsan_handle_type_mismatch, @function + +.extern __ubsan_handle_vla_bound_not_positive +.type __ubsan_handle_vla_bound_not_positive, @function + +.extern unlink_fs +.type unlink_fs, @function + +.extern unswitch_fpu +.type unswitch_fpu, @function + +.extern validate +.type validate, @function + +.extern valloc +.type valloc, @function + +.extern vasprintf +.type vasprintf, @function + +.extern vfs_install +.type vfs_install, @function + +.extern vfs_lock +.type vfs_lock, @function + +.extern vfs_mount +.type vfs_mount, @function + +.extern vfs_mount_type +.type vfs_mount_type, @function + +.extern vfs_register +.type vfs_register, @function + +.extern waitpid +.type waitpid, @function + +.extern wakeup_queue +.type wakeup_queue, @function + +.extern wakeup_queue_interrupted +.type wakeup_queue_interrupted, @function + +.extern wakeup_sleepers +.type wakeup_sleepers, @function + +.extern write_fs +.type write_fs, @function + +.extern write_pipe +.type write_pipe, @function + +.extern write_pty_master +.type write_pty_master, @function + +.extern write_pty_slave +.type write_pty_slave, @function + +.global kernel_symbols_start +kernel_symbols_start: + +.long alloc_frame +.asciz "alloc_frame" + +.long args_parse +.asciz "args_parse" + +.long args_present +.asciz "args_present" + +.long args_value +.asciz "args_value" + +.long assert_failed +.asciz "assert_failed" + +.long atoi +.asciz "atoi" + +.long bitset_clear +.asciz "bitset_clear" + +.long bitset_ffub +.asciz "bitset_ffub" + +.long bitset_free +.asciz "bitset_free" + +.long bitset_init +.asciz "bitset_init" + +.long bitset_set +.asciz "bitset_set" + +.long bitset_test +.asciz "bitset_test" + +.long boot_arg +.asciz "boot_arg" + +.long boot_arg_extra +.asciz "boot_arg_extra" + +.long boot_time +.asciz "boot_time" + +.long bss +.asciz "bss" + +.long calloc +.asciz "calloc" + +.long canonicalize_path +.asciz "canonicalize_path" + +.long chmod_fs +.asciz "chmod_fs" + +.long chown_fs +.asciz "chown_fs" + +.long cleanup_process +.asciz "cleanup_process" + +.long clear_frame +.asciz "clear_frame" + +.long clone +.asciz "clone" + +.long clone_directory +.asciz "clone_directory" + +.long clone_fs +.asciz "clone_fs" + +.long clone_table +.asciz "clone_table" + +.long close_fs +.asciz "close_fs" + +.long close_pipe +.asciz "close_pipe" + +.long close_pty_master +.asciz "close_pty_master" + +.long close_pty_slave +.asciz "close_pty_slave" + +.long cmdline +.asciz "cmdline" + +.long cmos_dump +.asciz "cmos_dump" + +.long code +.asciz "code" + +.long copy_multiboot +.asciz "copy_multiboot" + +.long copy_page_physical +.asciz "copy_page_physical" + +.long create_file_fs +.asciz "create_file_fs" + +.long create_kernel_tasklet +.asciz "create_kernel_tasklet" + +.long current_directory +.asciz "current_directory" + +.long current_process +.asciz "current_process" + +.long data +.asciz "data" + +.long debug_file +.asciz "debug_file" + +.long debug_hook +.asciz "debug_hook" + +.long debug_level +.asciz "debug_level" + +.long _debug_print +.asciz "_debug_print" + +.long debug_print_directory +.asciz "debug_print_directory" + +.long debug_print_process_tree +.asciz "debug_print_process_tree" + +.long debug_print_process_tree_node +.asciz "debug_print_process_tree_node" + +.long debug_print_vfs_tree +.asciz "debug_print_vfs_tree" + +.long debug_print_vfs_tree_node +.asciz "debug_print_vfs_tree_node" + +.long debug_video_crash +.asciz "debug_video_crash" + +.long default_name +.asciz "default_name" + +.long delete_process +.asciz "delete_process" + +.long disable_fpu +.asciz "disable_fpu" + +.long dma_frame +.asciz "dma_frame" + +.long dump_multiboot +.asciz "dump_multiboot" + +.long enable_fpu +.asciz "enable_fpu" + +.long end +.asciz "end" + +.long enter_signal_handler +.asciz "enter_signal_handler" + +.long enter_user_jmp +.asciz "enter_user_jmp" + +.long enter_userspace +.asciz "enter_userspace" + +.long exec +.asciz "exec" + +.long exec_elf +.asciz "exec_elf" + +.long exec_shebang +.asciz "exec_shebang" + +.long fault_handler +.asciz "fault_handler" + +.long finddir_fs +.asciz "finddir_fs" + +.long first_frame +.asciz "first_frame" + +.long first_n_frames +.asciz "first_n_frames" + +.long fix_signal_stacks +.asciz "fix_signal_stacks" + +.long fmts +.asciz "fmts" + +.long fork +.asciz "fork" + +.long fprintf +.asciz "fprintf" + +.long fpu_install +.asciz "fpu_install" + +.long fpu_thread +.asciz "fpu_thread" + +.long frames +.asciz "frames" + +.long free +.asciz "free" + +.long free_frame +.asciz "free_frame" + +.long frozen_stack +.asciz "frozen_stack" + +.long fs_root +.asciz "fs_root" + +.long fs_tree +.asciz "fs_tree" + +.long fs_types +.asciz "fs_types" + +.long gdt_flush +.asciz "gdt_flush" + +.long gdt_install +.asciz "gdt_install" + +.long gdt_set_gate +.asciz "gdt_set_gate" + +.long get_date +.asciz "get_date" + +.long get_mount_point +.asciz "get_mount_point" + +.long get_next_pid +.asciz "get_next_pid" + +.long get_page +.asciz "get_page" + +.long getpid +.asciz "getpid" + +.long get_time +.asciz "get_time" + +.long gettimeofday +.asciz "gettimeofday" + +.long halt_and_catch_fire +.asciz "halt_and_catch_fire" + +.long handle_signal +.asciz "handle_signal" + +.long hashmap_create +.asciz "hashmap_create" + +.long hashmap_create_int +.asciz "hashmap_create_int" + +.long hashmap_free +.asciz "hashmap_free" + +.long hashmap_get +.asciz "hashmap_get" + +.long hashmap_has +.asciz "hashmap_has" + +.long hashmap_int_comp +.asciz "hashmap_int_comp" + +.long hashmap_int_dupe +.asciz "hashmap_int_dupe" + +.long hashmap_int_hash +.asciz "hashmap_int_hash" + +.long hashmap_keys +.asciz "hashmap_keys" + +.long hashmap_remove +.asciz "hashmap_remove" + +.long hashmap_set +.asciz "hashmap_set" + +.long hashmap_string_comp +.asciz "hashmap_string_comp" + +.long hashmap_string_dupe +.asciz "hashmap_string_dupe" + +.long hashmap_string_hash +.asciz "hashmap_string_hash" + +.long hashmap_values +.asciz "hashmap_values" + +.long has_permission +.asciz "has_permission" + +.long heap_end +.asciz "heap_end" + +.long heap_install +.asciz "heap_install" + +.long idt_install +.asciz "idt_install" + +.long idt_load +.asciz "idt_load" + +.long idt_set_gate +.asciz "idt_set_gate" + +.long init_fpu +.asciz "init_fpu" + +.long initial_esp +.asciz "initial_esp" + +.long initialize_process_tree +.asciz "initialize_process_tree" + +.long inportb +.asciz "inportb" + +.long inportl +.asciz "inportl" + +.long inports +.asciz "inports" + +.long inportsm +.asciz "inportsm" + +.long int_disable +.asciz "int_disable" + +.long int_enable +.asciz "int_enable" + +.long int_resume +.asciz "int_resume" + +.long invalidate_page_tables +.asciz "invalidate_page_tables" + +.long invalidate_tables_at +.asciz "invalidate_tables_at" + +.long invalid_op +.asciz "invalid_op" + +.long ioctl_fs +.asciz "ioctl_fs" + +.long ioctl_pty_master +.asciz "ioctl_pty_master" + +.long ioctl_pty_slave +.asciz "ioctl_pty_slave" + +.long _irq0 +.asciz "_irq0" + +.long _irq1 +.asciz "_irq1" + +.long _irq10 +.asciz "_irq10" + +.long _irq11 +.asciz "_irq11" + +.long _irq12 +.asciz "_irq12" + +.long _irq13 +.asciz "_irq13" + +.long _irq14 +.asciz "_irq14" + +.long _irq15 +.asciz "_irq15" + +.long _irq2 +.asciz "_irq2" + +.long _irq3 +.asciz "_irq3" + +.long _irq4 +.asciz "_irq4" + +.long _irq5 +.asciz "_irq5" + +.long _irq6 +.asciz "_irq6" + +.long _irq7 +.asciz "_irq7" + +.long _irq8 +.asciz "_irq8" + +.long _irq9 +.asciz "_irq9" + +.long irq_ack +.asciz "irq_ack" + +.long irq_handler +.asciz "irq_handler" + +.long irq_install +.asciz "irq_install" + +.long irq_install_handler +.asciz "irq_install_handler" + +.long irq_uninstall_handler +.asciz "irq_uninstall_handler" + +.long isdeadly +.asciz "isdeadly" + +.long _isr0 +.asciz "_isr0" + +.long _isr1 +.asciz "_isr1" + +.long _isr10 +.asciz "_isr10" + +.long _isr11 +.asciz "_isr11" + +.long _isr12 +.asciz "_isr12" + +.long _isr127 +.asciz "_isr127" + +.long _isr13 +.asciz "_isr13" + +.long _isr14 +.asciz "_isr14" + +.long _isr15 +.asciz "_isr15" + +.long _isr16 +.asciz "_isr16" + +.long _isr17 +.asciz "_isr17" + +.long _isr18 +.asciz "_isr18" + +.long _isr19 +.asciz "_isr19" + +.long _isr2 +.asciz "_isr2" + +.long _isr20 +.asciz "_isr20" + +.long _isr21 +.asciz "_isr21" + +.long _isr22 +.asciz "_isr22" + +.long _isr23 +.asciz "_isr23" + +.long _isr24 +.asciz "_isr24" + +.long _isr25 +.asciz "_isr25" + +.long _isr26 +.asciz "_isr26" + +.long _isr27 +.asciz "_isr27" + +.long _isr28 +.asciz "_isr28" + +.long _isr29 +.asciz "_isr29" + +.long _isr3 +.asciz "_isr3" + +.long _isr30 +.asciz "_isr30" + +.long _isr31 +.asciz "_isr31" + +.long _isr4 +.asciz "_isr4" + +.long _isr5 +.asciz "_isr5" + +.long _isr6 +.asciz "_isr6" + +.long _isr7 +.asciz "_isr7" + +.long _isr8 +.asciz "_isr8" + +.long _isr9 +.asciz "_isr9" + +.long isrs_install +.asciz "isrs_install" + +.long isrs_install_handler +.asciz "isrs_install_handler" + +.long isrs_uninstall_handler +.asciz "isrs_uninstall_handler" + +.long is_update_in_progress +.asciz "is_update_in_progress" + +.long is_valid_process +.asciz "is_valid_process" + +.long __kernel_arch +.asciz "__kernel_arch" + +.long kernel_args_map +.asciz "kernel_args_map" + +.long __kernel_build_date +.asciz "__kernel_build_date" + +.long __kernel_build_time +.asciz "__kernel_build_time" + +.long __kernel_compiler_version +.asciz "__kernel_compiler_version" + +.long kernel_directory +.asciz "kernel_directory" + +.long kernel_heap_alloc_point +.asciz "kernel_heap_alloc_point" + +.long kernel_idle_task +.asciz "kernel_idle_task" + +.long __kernel_name +.asciz "__kernel_name" + +.long kernel_symbols_end +.asciz "kernel_symbols_end" + +.long kernel_symbols_start +.asciz "kernel_symbols_start" + +.long __kernel_version_codename +.asciz "__kernel_version_codename" + +.long __kernel_version_format +.asciz "__kernel_version_format" + +.long __kernel_version_lower +.asciz "__kernel_version_lower" + +.long __kernel_version_major +.asciz "__kernel_version_major" + +.long __kernel_version_minor +.asciz "__kernel_version_minor" + +.long __kernel_version_suffix +.asciz "__kernel_version_suffix" + +.long kexit +.asciz "kexit" + +.long kmain +.asciz "kmain" + +.long kmalloc +.asciz "kmalloc" + +.long kmalloc_p +.asciz "kmalloc_p" + +.long kmalloc_real +.asciz "kmalloc_real" + +.long kmalloc_startat +.asciz "kmalloc_startat" + +.long kopen +.asciz "kopen" + +.long kopen_recur +.asciz "kopen_recur" + +.long krand +.asciz "krand" + +.long kvmalloc +.asciz "kvmalloc" + +.long kvmalloc_p +.asciz "kvmalloc_p" + +.long lfind +.asciz "lfind" + +.long list_append +.asciz "list_append" + +.long list_append_after +.asciz "list_append_after" + +.long list_append_before +.asciz "list_append_before" + +.long list_copy +.asciz "list_copy" + +.long list_create +.asciz "list_create" + +.long list_delete +.asciz "list_delete" + +.long list_dequeue +.asciz "list_dequeue" + +.long list_destroy +.asciz "list_destroy" + +.long list_find +.asciz "list_find" + +.long list_free +.asciz "list_free" + +.long list_index_of +.asciz "list_index_of" + +.long list_insert +.asciz "list_insert" + +.long list_insert_after +.asciz "list_insert_after" + +.long list_insert_before +.asciz "list_insert_before" + +.long list_merge +.asciz "list_merge" + +.long list_pop +.asciz "list_pop" + +.long list_remove +.asciz "list_remove" + +.long make_pipe +.asciz "make_pipe" + +.long make_process_ready +.asciz "make_process_ready" + +.long make_unix_pipe +.asciz "make_unix_pipe" + +.long malloc +.asciz "malloc" + +.long map_to_physical +.asciz "map_to_physical" + +.long map_vfs_directory +.asciz "map_vfs_directory" + +.long mboot_ptr +.asciz "mboot_ptr" + +.long memchr +.asciz "memchr" + +.long memcmp +.asciz "memcmp" + +.long memcpy +.asciz "memcpy" + +.long memmove +.asciz "memmove" + +.long memory_total +.asciz "memory_total" + +.long memory_use +.asciz "memory_use" + +.long memrchr +.asciz "memrchr" + +.long memset +.asciz "memset" + +.long memsetw +.asciz "memsetw" + +.long mkdir_fs +.asciz "mkdir_fs" + +.long module_load +.asciz "module_load" + +.long module_load_direct +.asciz "module_load_direct" + +.long module_quickcheck +.asciz "module_quickcheck" + +.long modules_get_list +.asciz "modules_get_list" + +.long modules_get_symbols +.asciz "modules_get_symbols" + +.long modules_install +.asciz "modules_install" + +.long module_unload +.asciz "module_unload" + +.long next_pid +.asciz "next_pid" + +.long next_ready_process +.asciz "next_ready_process" + +.long nframes +.asciz "nframes" + +.long now +.asciz "now" + +.long num_syscalls +.asciz "num_syscalls" + +.long open_fs +.asciz "open_fs" + +.long open_pipe +.asciz "open_pipe" + +.long open_pty_master +.asciz "open_pty_master" + +.long open_pty_slave +.asciz "open_pty_slave" + +.long outportb +.asciz "outportb" + +.long outportl +.asciz "outportl" + +.long outports +.asciz "outports" + +.long outportsm +.asciz "outportsm" + +.long page_fault +.asciz "page_fault" + +.long paging_finalize +.asciz "paging_finalize" + +.long paging_install +.asciz "paging_install" + +.long paging_mark_system +.asciz "paging_mark_system" + +.long PciClassCodeTable +.asciz "PciClassCodeTable" + +.long PciCommandFlags +.asciz "PciCommandFlags" + +.long pci_device_lookup +.asciz "pci_device_lookup" + +.long PciDevSelFlags +.asciz "PciDevSelFlags" + +.long PciDevTable +.asciz "PciDevTable" + +.long pci_find_type +.asciz "pci_find_type" + +.long pci_read_field +.asciz "pci_read_field" + +.long pci_scan +.asciz "pci_scan" + +.long pci_scan_bus +.asciz "pci_scan_bus" + +.long pci_scan_func +.asciz "pci_scan_func" + +.long pci_scan_hit +.asciz "pci_scan_hit" + +.long pci_scan_slot +.asciz "pci_scan_slot" + +.long PciStatusFlags +.asciz "PciStatusFlags" + +.long pci_vendor_lookup +.asciz "pci_vendor_lookup" + +.long PciVenTable +.asciz "PciVenTable" + +.long pci_write_field +.asciz "pci_write_field" + +.long phys +.asciz "phys" + +.long pipe_size +.asciz "pipe_size" + +.long pipe_unsize +.asciz "pipe_unsize" + +.long placement_pointer +.asciz "placement_pointer" + +.long probable_function_name +.asciz "probable_function_name" + +.long process_alert_node +.asciz "process_alert_node" + +.long process_append_fd +.asciz "process_append_fd" + +.long process_available +.asciz "process_available" + +.long process_awaken_from_fswait +.asciz "process_awaken_from_fswait" + +.long process_compare +.asciz "process_compare" + +.long process_disown +.asciz "process_disown" + +.long process_from_pid +.asciz "process_from_pid" + +.long process_get_parent +.asciz "process_get_parent" + +.long process_is_ready +.asciz "process_is_ready" + +.long process_list +.asciz "process_list" + +.long process_move_fd +.asciz "process_move_fd" + +.long process_queue +.asciz "process_queue" + +.long process_tree +.asciz "process_tree" + +.long process_wait +.asciz "process_wait" + +.long process_wait_nodes +.asciz "process_wait_nodes" + +.long process_wake +.asciz "process_wake" + +.long pty_available_input +.asciz "pty_available_input" + +.long pty_available_output +.asciz "pty_available_output" + +.long pty_create +.asciz "pty_create" + +.long pty_install +.asciz "pty_install" + +.long pty_ioctl +.asciz "pty_ioctl" + +.long pty_list +.asciz "pty_list" + +.long pty_master_create +.asciz "pty_master_create" + +.long pty_new +.asciz "pty_new" + +.long pty_slave_create +.asciz "pty_slave_create" + +.long ramdisk +.asciz "ramdisk" + +.long ramdisk_mount +.asciz "ramdisk_mount" + +.long read_cmos +.asciz "read_cmos" + +.long readdir_fs +.asciz "readdir_fs" + +.long read_eip +.asciz "read_eip" + +.long read_fs +.asciz "read_fs" + +.long readlink_fs +.asciz "readlink_fs" + +.long read_pipe +.asciz "read_pipe" + +.long read_pty_master +.asciz "read_pty_master" + +.long read_pty_slave +.asciz "read_pty_slave" + +.long realloc +.asciz "realloc" + +.long reap_process +.asciz "reap_process" + +.long relative_time +.asciz "relative_time" + +.long release_directory +.asciz "release_directory" + +.long release_directory_for_exec +.asciz "release_directory_for_exec" + +.long restore_fpu +.asciz "restore_fpu" + +.long rets_from_sig +.asciz "rets_from_sig" + +.long return_from_signal_handler +.asciz "return_from_signal_handler" + +.long return_to_userspace +.asciz "return_to_userspace" + +.long rfind +.asciz "rfind" + +.long ring_buffer_available +.asciz "ring_buffer_available" + +.long ring_buffer_create +.asciz "ring_buffer_create" + +.long ring_buffer_destroy +.asciz "ring_buffer_destroy" + +.long ring_buffer_interrupt +.asciz "ring_buffer_interrupt" + +.long ring_buffer_read +.asciz "ring_buffer_read" + +.long ring_buffer_select_wait +.asciz "ring_buffer_select_wait" + +.long ring_buffer_size +.asciz "ring_buffer_size" + +.long ring_buffer_unread +.asciz "ring_buffer_unread" + +.long ring_buffer_write +.asciz "ring_buffer_write" + +.long save_fpu +.asciz "save_fpu" + +.long saves +.asciz "saves" + +.long sbrk +.asciz "sbrk" + +.long secs_of_month +.asciz "secs_of_month" + +.long secs_of_years +.asciz "secs_of_years" + +.long selectcheck_fs +.asciz "selectcheck_fs" + +.long selectwait_fs +.asciz "selectwait_fs" + +.long send_signal +.asciz "send_signal" + +.long set_fpu_cw +.asciz "set_fpu_cw" + +.long set_frame +.asciz "set_frame" + +.long set_kernel_stack +.asciz "set_kernel_stack" + +.long set_process_environment +.asciz "set_process_environment" + +.long shm_install +.asciz "shm_install" + +.long shm_obtain +.asciz "shm_obtain" + +.long shm_release +.asciz "shm_release" + +.long shm_release_all +.asciz "shm_release_all" + +.long shm_tree +.asciz "shm_tree" + +.long sleep_on +.asciz "sleep_on" + +.long sleep_queue +.asciz "sleep_queue" + +.long sleep_until +.asciz "sleep_until" + +.long spawn_init +.asciz "spawn_init" + +.long spawn_kidle +.asciz "spawn_kidle" + +.long spawn_process +.asciz "spawn_process" + +.long spin_init +.asciz "spin_init" + +.long spin_lock +.asciz "spin_lock" + +.long spin_unlock +.asciz "spin_unlock" + +.long spin_wait +.asciz "spin_wait" + +.long sprintf +.asciz "sprintf" + +.long start +.asciz "start" + +.long startswith +.asciz "startswith" + +.long stpcpy +.asciz "stpcpy" + +.long strchr +.asciz "strchr" + +.long strchrnul +.asciz "strchrnul" + +.long strcmp +.asciz "strcmp" + +.long strcpy +.asciz "strcpy" + +.long strcspn +.asciz "strcspn" + +.long strdup +.asciz "strdup" + +.long strlen +.asciz "strlen" + +.long strpbrk +.asciz "strpbrk" + +.long strrchr +.asciz "strrchr" + +.long strspn +.asciz "strspn" + +.long strstr +.asciz "strstr" + +.long strtok_r +.asciz "strtok_r" + +.long switch_fpu +.asciz "switch_fpu" + +.long switch_next +.asciz "switch_next" + +.long switch_page_directory +.asciz "switch_page_directory" + +.long switch_task +.asciz "switch_task" + +.long symbol_find +.asciz "symbol_find" + +.long symlink_fs +.asciz "symlink_fs" + +.long syscall_handler +.asciz "syscall_handler" + +.long syscalls_install +.asciz "syscalls_install" + +.long system +.asciz "system" + +.long task_exit +.asciz "task_exit" + +.long tasking_install +.asciz "tasking_install" + +.long test_frame +.asciz "test_frame" + +.long _timer_drift +.asciz "_timer_drift" + +.long timer_drift +.asciz "timer_drift" + +.long timer_handler +.asciz "timer_handler" + +.long timer_install +.asciz "timer_install" + +.long timer_phase +.asciz "timer_phase" + +.long timer_subticks +.asciz "timer_subticks" + +.long timer_ticks +.asciz "timer_ticks" + +.long tokenize +.asciz "tokenize" + +.long trace_pid +.asciz "trace_pid" + +.long tree_break_off +.asciz "tree_break_off" + +.long tree_count_children +.asciz "tree_count_children" + +.long tree_create +.asciz "tree_create" + +.long tree_destroy +.asciz "tree_destroy" + +.long tree_find +.asciz "tree_find" + +.long tree_find_parent +.asciz "tree_find_parent" + +.long tree_free +.asciz "tree_free" + +.long tree_node_create +.asciz "tree_node_create" + +.long tree_node_destroy +.asciz "tree_node_destroy" + +.long tree_node_find +.asciz "tree_node_find" + +.long tree_node_find_parent +.asciz "tree_node_find_parent" + +.long tree_node_free +.asciz "tree_node_free" + +.long tree_node_insert_child +.asciz "tree_node_insert_child" + +.long tree_node_insert_child_node +.asciz "tree_node_insert_child_node" + +.long tree_node_parent_remove +.asciz "tree_node_parent_remove" + +.long tree_node_remove +.asciz "tree_node_remove" + +.long tree_remove +.asciz "tree_remove" + +.long tree_remove_reparent_root +.asciz "tree_remove_reparent_root" + +.long tree_set_root +.asciz "tree_set_root" + +.long tss_flush +.asciz "tss_flush" + +.long ubsan_debug +.asciz "ubsan_debug" + +.long __ubsan_handle_add_overflow +.asciz "__ubsan_handle_add_overflow" + +.long __ubsan_handle_builtin_unreachable +.asciz "__ubsan_handle_builtin_unreachable" + +.long __ubsan_handle_divrem_overflow +.asciz "__ubsan_handle_divrem_overflow" + +.long __ubsan_handle_mul_overflow +.asciz "__ubsan_handle_mul_overflow" + +.long __ubsan_handle_negate_overflow +.asciz "__ubsan_handle_negate_overflow" + +.long __ubsan_handle_out_of_bounds +.asciz "__ubsan_handle_out_of_bounds" + +.long __ubsan_handle_shift_out_of_bounds +.asciz "__ubsan_handle_shift_out_of_bounds" + +.long __ubsan_handle_sub_overflow +.asciz "__ubsan_handle_sub_overflow" + +.long __ubsan_handle_type_mismatch +.asciz "__ubsan_handle_type_mismatch" + +.long __ubsan_handle_vla_bound_not_positive +.asciz "__ubsan_handle_vla_bound_not_positive" + +.long unlink_fs +.asciz "unlink_fs" + +.long unswitch_fpu +.asciz "unswitch_fpu" + +.long validate +.asciz "validate" + +.long valloc +.asciz "valloc" + +.long vasprintf +.asciz "vasprintf" + +.long vfs_install +.asciz "vfs_install" + +.long vfs_lock +.asciz "vfs_lock" + +.long vfs_mount +.asciz "vfs_mount" + +.long vfs_mount_type +.asciz "vfs_mount_type" + +.long vfs_register +.asciz "vfs_register" + +.long waitpid +.asciz "waitpid" + +.long wakeup_queue +.asciz "wakeup_queue" + +.long wakeup_queue_interrupted +.asciz "wakeup_queue_interrupted" + +.long wakeup_sleepers +.asciz "wakeup_sleepers" + +.long write_fs +.asciz "write_fs" + +.long write_pipe +.asciz "write_pipe" + +.long write_pty_master +.asciz "write_pty_master" + +.long write_pty_slave +.asciz "write_pty_slave" + +.global kernel_symbols_end +kernel_symbols_end: diff --git a/kernel/sys/module.c b/kernel/sys/module.c new file mode 100644 index 00000000..5bb80165 --- /dev/null +++ b/kernel/sys/module.c @@ -0,0 +1,390 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include +#include + +#define SYMBOLTABLE_HASHMAP_SIZE 10 +#define MODULE_HASHMAP_SIZE 10 + +static hashmap_t * symboltable = NULL; +static hashmap_t * modules = NULL; + +extern char kernel_symbols_start[]; +extern char kernel_symbols_end[]; + +typedef struct { + uintptr_t addr; + char name[]; +} kernel_symbol_t; + +/* Cannot use symboltable here because symbol_find is used during initialization + * of IRQs and ISRs. + */ +void (* symbol_find(const char * name))(void) { + kernel_symbol_t * k = (kernel_symbol_t *)&kernel_symbols_start; + + while ((uintptr_t)k < (uintptr_t)&kernel_symbols_end) { + if (strcmp(k->name, name)) { + k = (kernel_symbol_t *)((uintptr_t)k + sizeof *k + strlen(k->name) + 1); + continue; + } + return (void (*)(void))k->addr; + } + + return NULL; +} + +int module_quickcheck(void * blob) { + + Elf32_Header * target = (Elf32_Header *)blob; + char * head = (char *)blob; + + if (target->e_ident[0] != ELFMAG0 || + target->e_ident[1] != ELFMAG1 || + target->e_ident[2] != ELFMAG2 || + target->e_ident[3] != ELFMAG3) { + + goto _maybe_pack; + } + + if (target->e_type != ET_REL) { + goto _maybe_pack; + } + + return 1; + +_maybe_pack: + if (head[0] == 'P' && head[1] == 'A' && head[2] == 'C' && head[3] == 'K') { + return 2; + } + + return 0; +} + +void * module_load_direct(void * blob, size_t length) { + Elf32_Header * target = (Elf32_Header *)blob; + + if (target->e_ident[0] != ELFMAG0 || + target->e_ident[1] != ELFMAG1 || + target->e_ident[2] != ELFMAG2 || + target->e_ident[3] != ELFMAG3) { + + debug_print(ERROR, "Module is not a valid ELF object."); + + goto mod_load_error_unload; + } + + char * shstrtab = NULL; + char * symstrtab = NULL; + Elf32_Shdr * sym_shdr = NULL; + char * deps = NULL; + size_t deps_length = 0; + + /* TODO: Actually load the ELF somewhere! This is moronic, you're not initializing a BSS! */ + /* (and maybe keep the elf header somewhere) */ + + { + unsigned int i = 0; + for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { + Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); + if (i == target->e_shstrndx) { + shstrtab = (char *)((uintptr_t)target + shdr->sh_offset); + } + i++; + } + } + if (!shstrtab) { + debug_print(ERROR, "Could not locate module section header string table."); + goto mod_load_error_unload; + } + + { + for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { + Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); + if (shdr->sh_type == SHT_STRTAB && (!strcmp((char *)((uintptr_t)shstrtab + shdr->sh_name), ".strtab"))) { + symstrtab = (char *)((uintptr_t)target + shdr->sh_offset); + } + } + } + if (!shstrtab) { + debug_print(ERROR, "Could not locate module symbol string table."); + goto mod_load_error_unload; + } + + { + debug_print(INFO, "Checking dependencies."); + for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { + Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); + if ((!strcmp((char *)((uintptr_t)shstrtab + shdr->sh_name), "moddeps"))) { + deps = (char*)((Elf32_Addr)target + shdr->sh_offset); + deps_length = shdr->sh_size; + + unsigned int i = 0; + while (i < deps_length) { + if (strlen(&deps[i]) && !hashmap_get(modules, &deps[i])) { + debug_print(ERROR, " %s - not loaded", &deps[i]); + goto mod_load_error_unload; + } + debug_print(INFO, " %s", &deps[i]); + i += strlen(&deps[i]) + 1; + } + } + } + } + + { + for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { + Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); + if (shdr->sh_type == SHT_SYMTAB) { + sym_shdr = shdr; + } + } + } + if (!sym_shdr) { + debug_print(ERROR, "Could not locate section for symbol table."); + goto mod_load_error_unload; + } + + { + debug_print(INFO, "Loading sections."); + for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { + Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); + if (shdr->sh_type == SHT_NOBITS) { + shdr->sh_addr = (Elf32_Addr)malloc(shdr->sh_size); + memset((void *)shdr->sh_addr, 0x00, shdr->sh_size); + } else { + shdr->sh_addr = (Elf32_Addr)target + shdr->sh_offset; + } + } + } + + int undefined = 0; + + hashmap_t * local_symbols = hashmap_create(10); + { + Elf32_Sym * table = (Elf32_Sym *)((uintptr_t)target + sym_shdr->sh_offset); + while ((uintptr_t)table - ((uintptr_t)target + sym_shdr->sh_offset) < sym_shdr->sh_size) { + if (table->st_name) { + if (ELF32_ST_BIND(table->st_info) == STB_GLOBAL) { + char * name = (char *)((uintptr_t)symstrtab + table->st_name); + if (table->st_shndx == 0) { + if (!hashmap_get(symboltable, name)) { + debug_print(ERROR, "Unresolved symbol in module: %s", name); + undefined = 1; + } + } else { + Elf32_Shdr * s = NULL; + { + int i = 0; + int set = 0; + for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { + Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); + if (i == table->st_shndx) { + set = 1; + s = shdr; + break; + } + i++; + } + /* + * Common symbols + * If we were a proper linker, we'd look at a bunch of objects + * to find out if one of them defined this, but instead we have + * a strict hierarchy of symbol resolution, so we know that an + * undefined common symbol at this point should be immediately + * allocated and zeroed. + */ + if (!set && table->st_shndx == 65522) { + if (!hashmap_get(symboltable, name)) { + void * final = calloc(1, table->st_value); + debug_print(NOTICE, "point %s to 0x%x", name, (uintptr_t)final); + hashmap_set(symboltable, name, (void *)final); + hashmap_set(local_symbols, name, (void *)final); + } + } + } + if (s) { + uintptr_t final = s->sh_addr + table->st_value; + hashmap_set(symboltable, name, (void *)final); + hashmap_set(local_symbols, name, (void *)final); + } + } + } + } + table++; + } + } + if (undefined) { + debug_print(ERROR, "This module is faulty! Verify it specifies all of its"); + debug_print(ERROR, "dependencies properly with MODULE_DEPENDS."); + goto mod_load_error; + } + + { + for (unsigned int x = 0; x < (unsigned int)target->e_shentsize * target->e_shnum; x += target->e_shentsize) { + Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + x)); + if (shdr->sh_type == SHT_REL) { + Elf32_Rel * section_rel = (void *)(shdr->sh_addr); + Elf32_Rel * table = section_rel; + Elf32_Sym * symtable = (Elf32_Sym *)(sym_shdr->sh_addr); + while ((uintptr_t)table - (shdr->sh_addr) < shdr->sh_size) { + Elf32_Sym * sym = &symtable[ELF32_R_SYM(table->r_info)]; + Elf32_Shdr * rs = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + shdr->sh_info * target->e_shentsize)); + + uintptr_t addend = 0; + uintptr_t place = 0; + uintptr_t symbol = 0; + uintptr_t *ptr = NULL; + + if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { + Elf32_Shdr * s = (Elf32_Shdr *)((uintptr_t)target + (target->e_shoff + sym->st_shndx * target->e_shentsize)); + ptr = (uintptr_t *)(table->r_offset + rs->sh_addr); + addend = *ptr; + place = (uintptr_t)ptr; + symbol = s->sh_addr; + } else { + char * name = (char *)((uintptr_t)symstrtab + sym->st_name); + ptr = (uintptr_t *)(table->r_offset + rs->sh_addr); + addend = *ptr; + place = (uintptr_t)ptr; + if (!hashmap_get(symboltable, name)) { + debug_print(ERROR, "Wat? Missing symbol %s", name); + } + symbol = (uintptr_t)hashmap_get(symboltable, name); + } + switch (ELF32_R_TYPE(table->r_info)) { + case 1: + *ptr = addend + symbol; + break; + case 2: + *ptr = addend + symbol - place; + break; + default: + debug_print(ERROR, "Unsupported relocation type: %d", ELF32_R_TYPE(table->r_info)); + goto mod_load_error; + } + + table++; + } + } + } + } + + debug_print(INFO, "Locating module information..."); + module_defs * mod_info = NULL; + list_t * hash_keys = hashmap_keys(local_symbols); + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + if (startswith(key, "module_info_")) { + mod_info = hashmap_get(local_symbols, key); + } + } + list_free(hash_keys); + free(hash_keys); + if (!mod_info) { + debug_print(ERROR, "Failed to locate module information structure!"); + goto mod_load_error; + } + + mod_info->initialize(); + + debug_print(NOTICE, "Finished loading module %s", mod_info->name); + + /* We don't do this anymore + * TODO: Do this in the module unload function + hashmap_free(local_symbols); + free(local_symbols); + */ + + module_data_t * mod_data = malloc(sizeof(module_data_t)); + mod_data->mod_info = mod_info; + mod_data->bin_data = target; + mod_data->symbols = local_symbols; + mod_data->end = (uintptr_t)target + length; + mod_data->deps = deps; + mod_data->deps_length = deps_length; + + hashmap_set(modules, mod_info->name, (void *)mod_data); + + return mod_data; + +mod_load_error_unload: + return (void *)-1; + +mod_load_error: + return NULL; +} + +/** + * Install a module from a file and return + * a pointer to its module_info structure. + */ +void * module_load(char * filename) { + fs_node_t * file = kopen(filename, 0); + if (!file) { + debug_print(ERROR, "Failed to load module: %s", filename); + return NULL; + } + + debug_print(NOTICE, "Attempting to load kernel module: %s", filename); + + void * blob = (void *)kvmalloc(file->length); + read_fs(file, 0, file->length, (uint8_t *)blob); + + void * result = module_load_direct(blob, file->length); + + if (result == (void *)-1) { + debug_print(ERROR, "Error loading module."); + free(blob); + result = NULL; + } + + close_fs(file); + return result; +} + +/** + * Remove a loaded module. + */ +void module_unload(char * name) { + /* XXX: Lookup the module by name and verify it has no dependencies loaded. */ + /* XXX: Call module_info->finish() */ + /* XXX: Unmap symbols defined the module that weren't otherwise defined. */ + /* XXX: Deallocate the regions the module was mapped into */ +} + +void modules_install(void) { + /* Initialize the symboltable, we use a hashmap of symbols to addresses */ + symboltable = hashmap_create(SYMBOLTABLE_HASHMAP_SIZE); + + /* Load all of the kernel symbols into the symboltable */ + kernel_symbol_t * k = (kernel_symbol_t *)&kernel_symbols_start; + + while ((uintptr_t)k < (uintptr_t)&kernel_symbols_end) { + hashmap_set(symboltable, k->name, (void *)k->addr); + k = (kernel_symbol_t *)((uintptr_t)k + sizeof(kernel_symbol_t) + strlen(k->name) + 1); + } + + /* Also add the kernel_symbol_start and kernel_symbol_end (these were excluded from the generator) */ + hashmap_set(symboltable, "kernel_symbols_start", &kernel_symbols_start); + hashmap_set(symboltable, "kernel_symbols_end", &kernel_symbols_end); + + /* Initialize the module name -> object hashmap */ + modules = hashmap_create(MODULE_HASHMAP_SIZE); +} + +/* Accessors. */ +hashmap_t * modules_get_list(void) { + return modules; +} + +hashmap_t * modules_get_symbols(void) { + return symboltable; +} diff --git a/kernel/sys/panic.c b/kernel/sys/panic.c new file mode 100644 index 00000000..c8ca91b8 --- /dev/null +++ b/kernel/sys/panic.c @@ -0,0 +1,103 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * + * Panic functions + */ +#include +#include +#include +#include + +void halt_and_catch_fire(char * error_message, const char * file, int line, struct regs * regs) { + IRQ_OFF; + debug_print(ERROR, "HACF: %s", error_message); + debug_print(ERROR, "Proc: %d", getpid()); + debug_print(ERROR, "File: %s", file); + debug_print(ERROR, "Line: %d", line); + if (regs) { + debug_print(ERROR, "Registers at interrupt:"); + debug_print(ERROR, "eax=0x%x ebx=0x%x", regs->eax, regs->ebx); + debug_print(ERROR, "ecx=0x%x edx=0x%x", regs->ecx, regs->edx); + debug_print(ERROR, "esp=0x%x ebp=0x%x", regs->esp, regs->ebp); + debug_print(ERROR, "Error code: 0x%x", regs->err_code); + debug_print(ERROR, "EFLAGS: 0x%x", regs->eflags); + debug_print(ERROR, "User ESP: 0x%x", regs->useresp); + debug_print(ERROR, "eip=0x%x", regs->eip); + } + debug_print(ERROR, "This process has been descheduled."); + kexit(1); +} + +char * probable_function_name(uintptr_t ip, uintptr_t * out_addr) { + char * closest = NULL; + size_t distance = 0xFFFFFFFF; + uintptr_t addr = 0; + + if (modules_get_symbols()) { + list_t * hash_keys = hashmap_keys(modules_get_symbols()); + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + uintptr_t a = (uintptr_t)hashmap_get(modules_get_symbols(), key); + + if (!a) continue; + + size_t d = 0xFFFFFFFF; + if (a <= ip) { + d = ip - a; + } + if (d < distance) { + closest = key; + distance = d; + addr = a; + } + } + free(hash_keys); + + } + *out_addr = addr; + return closest; +} + +void assert_failed(const char *file, uint32_t line, const char *desc) { + IRQ_OFF; + debug_print(INSANE, "Kernel Assertion Failed: %s", desc); + debug_print(INSANE, "File: %s", file); + debug_print(INSANE, "Line: %d", line); + debug_print(INSANE, "System Halted!"); + +#if 1 + unsigned int * ebp = (unsigned int *)(&file - 2); + + debug_print(INSANE, "Stack trace:"); + + for (unsigned int frame = 0; frame < 20; ++frame) { + unsigned int eip = ebp[1]; + if (eip == 0) break; + ebp = (unsigned int *)(ebp[0]); + unsigned int * args = &ebp[2]; + (void)args; + uintptr_t addr; + char * func = probable_function_name(eip, &addr); + debug_print(INSANE, " 0x%x (%s+%d)\n", eip, func, eip-addr); + } + + +#endif + + if (debug_video_crash) { + char msg[4][256]; + sprintf(msg[0], "Kernel Assertion Failed: %s", desc); + sprintf(msg[1], "File: %s", file); + sprintf(msg[2], "Line: %d", line); + sprintf(msg[3], "System Halted!"); + char * msgs[] = {msg[0], msg[1], msg[2], msg[3], NULL}; + debug_video_crash(msgs); + } + + while (1) { + IRQ_OFF; + PAUSE; + } +} diff --git a/kernel/sys/process.c b/kernel/sys/process.c new file mode 100644 index 00000000..b38ed760 --- /dev/null +++ b/kernel/sys/process.c @@ -0,0 +1,963 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2012 Markus Schober + * Copyright (C) 2015 Dale Weiler + * + * Processes + * + * Internal format format for a process and functions to spawn + * new processes and manage the process tree. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +tree_t * process_tree; /* Parent->Children tree */ +list_t * process_list; /* Flat storage */ +list_t * process_queue; /* Ready queue */ +list_t * sleep_queue; +volatile process_t * current_process = NULL; +process_t * kernel_idle_task = NULL; + +static spin_lock_t tree_lock = { 0 }; +static spin_lock_t process_queue_lock = { 0 }; +static spin_lock_t wait_lock_tmp = { 0 }; +static spin_lock_t sleep_lock = { 0 }; + +static bitset_t pid_set; + +/* Default process name string */ +char * default_name = "[unnamed]"; + +int is_valid_process(process_t * process) { + foreach(lnode, process_list) { + if (lnode->value == process) { + return 1; + } + } + + return 0; +} + +/* + * This makes a nice 4096-byte bitmap. It also happens + * to be pid_max on 32-bit Linux, so that's kinda nice. + */ +#define MAX_PID 32768 + +/* + * Initialize the process tree and ready queue. + */ +void initialize_process_tree(void) { + process_tree = tree_create(); + process_list = list_create(); + process_queue = list_create(); + sleep_queue = list_create(); + + /* Start off with enough bits for 64 processes */ + bitset_init(&pid_set, MAX_PID / 8); + /* First two bits are set by default */ + bitset_set(&pid_set, 0); + bitset_set(&pid_set, 1); +} + +/* + * Recursively print a process node to the console. + * + * @param node Node to print. + * @param height Current depth in the tree. + */ +void debug_print_process_tree_node(tree_node_t * node, size_t height) { + /* End recursion on a blank entry */ + if (!node) return; + char * tmp = malloc(512); + memset(tmp, 0, 512); + char * c = tmp; + /* Indent output */ + for (uint32_t i = 0; i < height; ++i) { + c += sprintf(c, " "); + } + /* Get the current process */ + process_t * proc = (process_t *)node->value; + /* Print the process name */ + c += sprintf(c, "%d.%d %s", proc->group ? proc->group : proc->id, proc->id, proc->name); + if (proc->description) { + /* And, if it has one, its description */ + c += sprintf(c, " %s", proc->description); + } + if (proc->finished) { + c += sprintf(c, " [zombie]"); + } + /* Linefeed */ + debug_print(NOTICE, "%s", tmp); + free(tmp); + foreach(child, node->children) { + /* Recursively print the children */ + debug_print_process_tree_node(child->value, height + 1); + } +} + +/* + * Print the process tree to the console. + */ +void debug_print_process_tree(void) { + debug_print_process_tree_node(process_tree->root, 0); +} + +/* + * Retreive the next ready process. + * XXX: POPs from the ready queue! + * + * @return A pointer to the next process in the queue. + */ +process_t * next_ready_process(void) { + if (!process_available()) { + return kernel_idle_task; + } + if (process_queue->head->owner != process_queue) { + debug_print(ERROR, "Erroneous process located in process queue: node 0x%x has owner 0x%x, but process_queue is 0x%x", process_queue->head, process_queue->head->owner, process_queue); + + process_t * proc = process_queue->head->value; + + debug_print(ERROR, "PID associated with this node is %d", proc->id); + } + node_t * np = list_dequeue(process_queue); + assert(np && "Ready queue is empty."); + process_t * next = np->value; + return next; +} + +/* + * Reinsert a process into the ready queue. + * + * @param proc Process to reinsert + */ +void make_process_ready(process_t * proc) { + if (proc->sleep_node.owner != NULL) { + if (proc->sleep_node.owner == sleep_queue) { + /* XXX can't wake from timed sleep */ + if (proc->timed_sleep_node) { + IRQ_OFF; + spin_lock(sleep_lock); + list_delete(sleep_queue, proc->timed_sleep_node); + spin_unlock(sleep_lock); + IRQ_RES; + proc->sleep_node.owner = NULL; + free(proc->timed_sleep_node->value); + } + /* Else: I have no idea what happened. */ + } else { + proc->sleep_interrupted = 1; + spin_lock(wait_lock_tmp); + list_delete((list_t*)proc->sleep_node.owner, &proc->sleep_node); + spin_unlock(wait_lock_tmp); + } + } + if (proc->sched_node.owner) { + debug_print(WARNING, "Can't make process ready without removing from owner list: %d", proc->id); + debug_print(WARNING, " (This is a bug) Current owner list is 0x%x (ready queue is 0x%x)", proc->sched_node.owner, process_queue); + return; + } + spin_lock(process_queue_lock); + list_append(process_queue, &proc->sched_node); + spin_unlock(process_queue_lock); +} + + +extern void tree_remove_reparent_root(tree_t * tree, tree_node_t * node); + +/* + * Delete a process from the process tree + * + * @param proc Process to find and remove. + */ +void delete_process(process_t * proc) { + tree_node_t * entry = proc->tree_entry; + + /* The process must exist in the tree, or the client is at fault */ + if (!entry) return; + + /* We can not remove the root, which is an error anyway */ + assert((entry != process_tree->root) && "Attempted to kill init."); + + if (process_tree->root == entry) { + /* We are init, don't even bother. */ + return; + } + + /* Remove the entry. */ + spin_lock(tree_lock); + /* Reparent everyone below me to init */ + int has_children = entry->children->length; + tree_remove_reparent_root(process_tree, entry); + list_delete(process_list, list_find(process_list, proc)); + spin_unlock(tree_lock); + + if (has_children) { + process_t * init = process_tree->root->value; + wakeup_queue(init->wait_queue); + } + + bitset_clear(&pid_set, proc->id); + + /* Uh... */ + free(proc); +} + +static void _kidle(void) { + while (1) { + IRQ_ON; + PAUSE; + } +} + +/* + * Spawn the idle "process". + */ +process_t * spawn_kidle(void) { + process_t * idle = malloc(sizeof(process_t)); + memset(idle, 0x00, sizeof(process_t)); + idle->id = -1; + idle->name = strdup("[kidle]"); + idle->is_tasklet = 1; + + idle->image.stack = (uintptr_t)malloc(KERNEL_STACK_SIZE) + KERNEL_STACK_SIZE; + idle->thread.eip = (uintptr_t)&_kidle; + idle->thread.esp = idle->image.stack; + idle->thread.ebp = idle->image.stack; + + idle->started = 1; + idle->running = 1; + idle->wait_queue = list_create(); + idle->shm_mappings = list_create(); + idle->signal_queue = list_create(); + + gettimeofday(&idle->start, NULL); + + set_process_environment(idle, current_directory); + return idle; +} + +/* + * Spawn the initial process. + * + * @return A pointer to the new initial process entry + */ +process_t * spawn_init(void) { + /* We can only do this once. */ + assert((!process_tree->root) && "Tried to regenerate init!"); + + /* Allocate space for a new process */ + process_t * init = malloc(sizeof(process_t)); + /* Set it as the root process */ + tree_set_root(process_tree, (void *)init); + /* Set its tree entry pointer so we can keep track + * of the process' entry in the process tree. */ + init->tree_entry = process_tree->root; + init->id = 1; /* Init is PID 1 */ + init->group = 0; + init->name = strdup("init"); /* Um, duh. */ + init->cmdline = NULL; + init->user = 0; /* UID 0 */ + init->mask = 022; /* umask */ + init->group = 0; /* Task group 0 */ + init->status = 0; /* Run status */ + init->fds = malloc(sizeof(fd_table_t)); + init->fds->refs = 1; + init->fds->length = 0; /* Initialize the file descriptors */ + init->fds->capacity = 4; + init->fds->entries = malloc(sizeof(fs_node_t *) * init->fds->capacity); + + /* Set the working directory */ + init->wd_node = clone_fs(fs_root); + init->wd_name = strdup("/"); + + /* Heap and stack pointers (and actuals) */ + init->image.entry = 0; + init->image.heap = 0; + init->image.heap_actual = 0; + init->image.stack = initial_esp + 1; + init->image.user_stack = 0; + init->image.size = 0; + init->image.shm_heap = SHM_START; /* Yeah, a bit of a hack. */ + + spin_init(init->image.lock); + + /* Process is not finished */ + init->finished = 0; + init->started = 1; + init->running = 1; + init->wait_queue = list_create(); + init->shm_mappings = list_create(); + init->signal_queue = list_create(); + init->signal_kstack = NULL; /* None yet initialized */ + + init->sched_node.prev = NULL; + init->sched_node.next = NULL; + init->sched_node.value = init; + + init->sleep_node.prev = NULL; + init->sleep_node.next = NULL; + init->sleep_node.value = init; + + init->timed_sleep_node = NULL; + + init->is_tasklet = 0; + + set_process_environment(init, current_directory); + + /* What the hey, let's also set the description on this one */ + init->description = strdup("[init]"); + list_insert(process_list, (void *)init); + + return init; +} + +/* + * Get the next available PID + * + * @return A usable PID for a new process. + */ +static int _next_pid = 2; +pid_t get_next_pid(void) { + if (_next_pid > MAX_PID) { + int index = bitset_ffub(&pid_set); + /* + * Honestly, we don't have the memory to really risk reaching + * the point where we have MAX_PID processes running + * concurrently, so this assertion should be "safe enough". + */ + assert(index != -1); + bitset_set(&pid_set, index); + return index; + } + int pid = _next_pid; + _next_pid++; + assert(!bitset_test(&pid_set, pid) && "Next PID already allocated?"); + bitset_set(&pid_set, pid); + return pid; +} + +/* + * Disown a process from its parent. + */ +void process_disown(process_t * proc) { + assert(process_tree->root && "No init, has the process tree been initialized?"); + + /* Find the process in the tree */ + tree_node_t * entry = proc->tree_entry; + /* Break it of from its current parent */ + spin_lock(tree_lock); + tree_break_off(process_tree, entry); + /* And insert it back elsewhere */ + tree_node_insert_child_node(process_tree, process_tree->root, entry); + spin_unlock(tree_lock); +} + +/* + * Spawn a new process. + * + * @param parent The parent process to spawn the new one off of. + * @return A pointer to the new process. + */ +process_t * spawn_process(volatile process_t * parent, int reuse_fds) { + assert(process_tree->root && "Attempted to spawn a process without init."); + + /* Allocate a new process */ + debug_print(INFO," process_t {"); + process_t * proc = calloc(sizeof(process_t),1); + debug_print(INFO," }"); + proc->id = get_next_pid(); /* Set its PID */ + proc->group = proc->id; /* Set the GID */ + proc->name = strdup(parent->name); /* Use the default name */ + proc->description = NULL; /* No description */ + proc->cmdline = parent->cmdline; + + /* Copy permissions */ + proc->user = parent->user; + proc->mask = parent->mask; + + /* XXX this is wrong? */ + proc->group = parent->group; + + /* Zero out the ESP/EBP/EIP */ + proc->thread.esp = 0; + proc->thread.ebp = 0; + proc->thread.eip = 0; + proc->thread.fpu_enabled = 0; + memcpy((void*)proc->thread.fp_regs, (void*)parent->thread.fp_regs, 512); + + /* Set the process image information from the parent */ + proc->image.entry = parent->image.entry; + proc->image.heap = parent->image.heap; + proc->image.heap_actual = parent->image.heap_actual; + proc->image.size = parent->image.size; + debug_print(INFO," stack {"); + proc->image.stack = (uintptr_t)kvmalloc(KERNEL_STACK_SIZE) + KERNEL_STACK_SIZE; + debug_print(INFO," }"); + proc->image.user_stack = parent->image.user_stack; + proc->image.shm_heap = SHM_START; /* Yeah, a bit of a hack. */ + + spin_init(proc->image.lock); + + assert(proc->image.stack && "Failed to allocate kernel stack for new process."); + + /* Clone the file descriptors from the original process */ + if (reuse_fds) { + proc->fds = parent->fds; + proc->fds->refs++; + } else { + proc->fds = malloc(sizeof(fd_table_t)); + proc->fds->refs = 1; + proc->fds->length = parent->fds->length; + proc->fds->capacity = parent->fds->capacity; + debug_print(INFO," fds / files {"); + proc->fds->entries = malloc(sizeof(fs_node_t *) * proc->fds->capacity); + assert(proc->fds->entries && "Failed to allocate file descriptor table for new process."); + debug_print(INFO," ---"); + for (uint32_t i = 0; i < parent->fds->length; ++i) { + proc->fds->entries[i] = clone_fs(parent->fds->entries[i]); + } + debug_print(INFO," }"); + } + + /* As well as the working directory */ + proc->wd_node = clone_fs(parent->wd_node); + proc->wd_name = strdup(parent->wd_name); + + /* Zero out the process status */ + proc->status = 0; + proc->finished = 0; + proc->started = 0; + proc->running = 0; + memset(proc->signals.functions, 0x00, sizeof(uintptr_t) * NUMSIGNALS); + proc->wait_queue = list_create(); + proc->shm_mappings = list_create(); + proc->signal_queue = list_create(); + proc->signal_kstack = NULL; /* None yet initialized */ + + proc->sched_node.prev = NULL; + proc->sched_node.next = NULL; + proc->sched_node.value = proc; + + proc->sleep_node.prev = NULL; + proc->sleep_node.next = NULL; + proc->sleep_node.value = proc; + + proc->timed_sleep_node = NULL; + + proc->is_tasklet = 0; + + gettimeofday(&proc->start, NULL); + + /* Insert the process into the process tree as a child + * of the parent process. */ + tree_node_t * entry = tree_node_create(proc); + assert(entry && "Failed to allocate a process tree node for new process."); + proc->tree_entry = entry; + spin_lock(tree_lock); + tree_node_insert_child_node(process_tree, parent->tree_entry, entry); + list_insert(process_list, (void *)proc); + spin_unlock(tree_lock); + + /* Return the new process */ + return proc; +} + +uint8_t process_compare(void * proc_v, void * pid_v) { + pid_t pid = (*(pid_t *)pid_v); + process_t * proc = (process_t *)proc_v; + + return (uint8_t)(proc->id == pid); +} + +process_t * process_from_pid(pid_t pid) { + if (pid < 0) return NULL; + + spin_lock(tree_lock); + tree_node_t * entry = tree_find(process_tree,&pid,process_compare); + spin_unlock(tree_lock); + if (entry) { + return (process_t *)entry->value; + } + return NULL; +} + +process_t * process_get_parent(process_t * process) { + process_t * result = NULL; + spin_lock(tree_lock); + + tree_node_t * entry = process->tree_entry; + + if (entry->parent) { + result = entry->parent->value; + } + + spin_unlock(tree_lock); + return result; +} + +/* + * Wait for children. + * + * @param process Process doing the waiting. + * @param pid PID to wait for + * @param status [out] Where to put the status conditions of the waited-for process + * @param options Options (unused) + * @return A pointer to the process that broke the wait + */ +process_t * process_wait(process_t * process, pid_t pid, int * status, int options) { + /* `options` is ignored */ + if (pid == -1) { + /* wait for any child process */ + } else if (pid < 0) { + /* wait for any porcess whose ->group == processes[abs(pid)]->group */ + } else if (pid == 0) { + /* wait for any process whose ->group == process->group */ + } else { + /* wait for processes[pid] */ + } + return NULL; +} + +/* + * Wake up a sleeping process + * + * @param process Process to wake up + * @param caller Who woke it up + * @return Don't know yet, but I think it should return something. + */ +int process_wake(process_t * process, process_t * caller) { + + return 0; +} + +/* + * Set the directory for a process. + * + * @param proc Process to set the directory for. + * @param directory Directory to set. + */ +void set_process_environment(process_t * proc, page_directory_t * directory) { + assert(proc); + assert(directory); + + proc->thread.page_directory = directory; +} + +/* + * Are there any processes available in the queue? + * (Queue not empty) + * + * @return 1 if there are processes available, 0 otherwise + */ +uint8_t process_available(void) { + return (process_queue->head != NULL); +} + +/* + * Append a file descriptor to a process. + * + * @param proc Process to append to + * @param node The VFS node + * @return The actual fd, for use in userspace + */ +uint32_t process_append_fd(process_t * proc, fs_node_t * node) { + /* Fill gaps */ + for (unsigned int i = 0; i < proc->fds->length; ++i) { + if (!proc->fds->entries[i]) { + proc->fds->entries[i] = node; + return i; + } + } + /* No gaps, expand */ + if (proc->fds->length == proc->fds->capacity) { + proc->fds->capacity *= 2; + proc->fds->entries = realloc(proc->fds->entries, sizeof(fs_node_t *) * proc->fds->capacity); + } + proc->fds->entries[proc->fds->length] = node; + proc->fds->length++; + return proc->fds->length-1; +} + +/* + * dup2() -> Move the file pointed to by `s(ou)rc(e)` into + * the slot pointed to be `dest(ination)`. + * + * @param proc Process to do this for + * @param src Source file descriptor + * @param dest Destination file descriptor + * @return The destination file descriptor, -1 on failure + */ +uint32_t process_move_fd(process_t * proc, int src, int dest) { + if ((size_t)src > proc->fds->length || (dest != -1 && (size_t)dest > proc->fds->length)) { + return -1; + } + if (dest == -1) { + dest = process_append_fd(proc, NULL); + } + if (proc->fds->entries[dest] != proc->fds->entries[src]) { + close_fs(proc->fds->entries[dest]); + proc->fds->entries[dest] = proc->fds->entries[src]; + open_fs(proc->fds->entries[dest], 0); + } + return dest; +} + +int wakeup_queue(list_t * queue) { + int awoken_processes = 0; + while (queue->length > 0) { + spin_lock(wait_lock_tmp); + node_t * node = list_pop(queue); + spin_unlock(wait_lock_tmp); + if (!((process_t *)node->value)->finished) { + make_process_ready(node->value); + } + awoken_processes++; + } + return awoken_processes; +} + +int wakeup_queue_interrupted(list_t * queue) { + int awoken_processes = 0; + while (queue->length > 0) { + spin_lock(wait_lock_tmp); + node_t * node = list_pop(queue); + spin_unlock(wait_lock_tmp); + if (!((process_t *)node->value)->finished) { + process_t * proc = node->value; + proc->sleep_interrupted = 1; + make_process_ready(proc); + } + awoken_processes++; + } + return awoken_processes; +} + + +int sleep_on(list_t * queue) { + if (current_process->sleep_node.owner) { + /* uh, we can't sleep right now, we're marked as ready */ + switch_task(0); + return 0; + } + current_process->sleep_interrupted = 0; + spin_lock(wait_lock_tmp); + list_append(queue, (node_t *)¤t_process->sleep_node); + spin_unlock(wait_lock_tmp); + switch_task(0); + return current_process->sleep_interrupted; +} + +int process_is_ready(process_t * proc) { + return (proc->sched_node.owner != NULL); +} + + +void wakeup_sleepers(unsigned long seconds, unsigned long subseconds) { + IRQ_OFF; + spin_lock(sleep_lock); + if (sleep_queue->length) { + sleeper_t * proc = ((sleeper_t *)sleep_queue->head->value); + while (proc && (proc->end_tick < seconds || (proc->end_tick == seconds && proc->end_subtick <= subseconds))) { + + if (proc->is_fswait) { + proc->is_fswait = -1; + process_alert_node(proc->process,proc); + } else { + process_t * process = proc->process; + process->sleep_node.owner = NULL; + process->timed_sleep_node = NULL; + if (!process_is_ready(process)) { + make_process_ready(process); + } + } + free(proc); + free(list_dequeue(sleep_queue)); + if (sleep_queue->length) { + proc = ((sleeper_t *)sleep_queue->head->value); + } else { + break; + } + } + } + spin_unlock(sleep_lock); + IRQ_RES; +} + +void sleep_until(process_t * process, unsigned long seconds, unsigned long subseconds) { + if (current_process->sleep_node.owner) { + /* Can't sleep, sleeping already */ + return; + } + process->sleep_node.owner = sleep_queue; + + IRQ_OFF; + spin_lock(sleep_lock); + node_t * before = NULL; + foreach(node, sleep_queue) { + sleeper_t * candidate = ((sleeper_t *)node->value); + if (candidate->end_tick > seconds || (candidate->end_tick == seconds && candidate->end_subtick > subseconds)) { + break; + } + before = node; + } + sleeper_t * proc = malloc(sizeof(sleeper_t)); + proc->process = process; + proc->end_tick = seconds; + proc->end_subtick = subseconds; + proc->is_fswait = 0; + process->timed_sleep_node = list_insert_after(sleep_queue, before, proc); + spin_unlock(sleep_lock); + IRQ_RES; +} + +void cleanup_process(process_t * proc, int retval) { + proc->status = retval; + proc->finished = 1; + + list_free(proc->wait_queue); + free(proc->wait_queue); + list_free(proc->signal_queue); + free(proc->signal_queue); + free(proc->wd_name); + + + if (proc->node_waits) { + list_free(proc->node_waits); + free(proc->node_waits); + proc->node_waits = NULL; + } + debug_print(INFO, "Releasing shared memory for %d", proc->id); + shm_release_all(proc); + free(proc->shm_mappings); + debug_print(INFO, "Freeing more mems %d", proc->id); + if (proc->signal_kstack) { + free(proc->signal_kstack); + } + + release_directory(proc->thread.page_directory); + + debug_print(INFO, "Dec'ing fds for %d", proc->id); + proc->fds->refs--; + if (proc->fds->refs == 0) { + debug_print(INFO, "Reached 0, all dependencies are closed for %d's file descriptors and page directories", proc->id); + debug_print(INFO, "Going to clear out the file descriptors %d", proc->id); + for (uint32_t i = 0; i < proc->fds->length; ++i) { + if (proc->fds->entries[i]) { + close_fs(proc->fds->entries[i]); + proc->fds->entries[i] = NULL; + } + } + debug_print(INFO, "... and their storage %d", proc->id); + free(proc->fds->entries); + free(proc->fds); + debug_print(INFO, "... and the kernel stack (hope this ain't us) %d", proc->id); + free((void *)(proc->image.stack - KERNEL_STACK_SIZE)); + } +} + +void reap_process(process_t * proc) { + debug_print(INFO, "Reaping process %d; mem before = %d", proc->id, memory_use()); + free(proc->name); + debug_print(INFO, "Reaped process %d; mem after = %d", proc->id, memory_use()); + + delete_process(proc); + debug_print_process_tree(); +} + +static int wait_candidate(process_t * parent, int pid, int options, process_t * proc) { + (void)options; /* there is only one option that affects candidacy, and we don't support it yet */ + + if (!proc) return 0; + + if (pid < -1) { + if (proc->group == -pid || proc->id == -pid) return 1; + } else if (pid == 0) { + /* Matches our group ID */ + if (proc->group == parent->id) return 1; + } else if (pid > 0) { + /* Specific pid */ + if (proc->id == pid) return 1; + } else { + return 1; + } + return 0; +} + +int waitpid(int pid, int * status, int options) { + process_t * proc = (process_t *)current_process; + if (proc->group) { + proc = process_from_pid(proc->group); + } + + debug_print(INFO, "waitpid(%s%d, ..., %d) (from pid=%d.%d)", (pid >= 0) ? "" : "-", (pid >= 0) ? pid : -pid, options, current_process->id, current_process->group); + + do { + process_t * candidate = NULL; + int has_children = 0; + + /* First, find out if there is anyone to reap */ + foreach(node, proc->tree_entry->children) { + if (!node->value) { + continue; + } + process_t * child = ((tree_node_t *)node->value)->value; + + if (wait_candidate(proc, pid, options, child)) { + has_children = 1; + if (child->finished) { + candidate = child; + break; + } + } + } + + if (!has_children) { + /* No valid children matching this description */ + debug_print(INFO, "No children matching description."); + return -ECHILD; + } + + if (candidate) { + debug_print(INFO, "Candidate found (%x:%d), bailing early.", candidate, candidate->id); + if (status) { + *status = candidate->status; + } + int pid = candidate->id; + reap_process(candidate); + return pid; + } else { + if (options & 1) { + return 0; + } + debug_print(INFO, "Sleeping until queue is done."); + /* Wait */ + if (sleep_on(proc->wait_queue) != 0) { + debug_print(INFO, "wait() was interrupted"); + return -EINTR; + } + } + } while (1); +} + +int process_wait_nodes(process_t * process,fs_node_t * nodes[], int timeout) { + assert(!process->node_waits && "Tried to wait on nodes while already waiting on nodes."); + + fs_node_t ** n = nodes; + int index = 0; + if (*n) { + do { + int result = selectcheck_fs(*n); + if (result < 0) { + debug_print(NOTICE, "An invalid descriptor was specified: %d (0x%x) (pid=%d)", index, *n, current_process->id); + return -1; + } + if (result == 0) { + return index; + } + n++; + index++; + } while (*n); + } + + if (timeout == 0) { + return -2; + } + + n = nodes; + + process->node_waits = list_create(); + if (*n) { + do { + if (selectwait_fs(*n, process) < 0) { + debug_print(NOTICE, "Bad selectwait? 0x%x", *n); + } + n++; + } while (*n); + } + + if (timeout > 0) { + debug_print(INFO, "fswait with a timeout of %d (pid=%d)", timeout, current_process->id); + unsigned long s, ss; + relative_time(0, timeout, &s, &ss); + + IRQ_OFF; + spin_lock(sleep_lock); + node_t * before = NULL; + foreach(node, sleep_queue) { + sleeper_t * candidate = ((sleeper_t *)node->value); + if (candidate->end_tick > s || (candidate->end_tick == s && candidate->end_subtick > ss)) { + break; + } + before = node; + } + sleeper_t * proc = malloc(sizeof(sleeper_t)); + proc->process = process; + proc->end_tick = s; + proc->end_subtick = ss; + proc->is_fswait = 1; + list_insert(((process_t *)process)->node_waits, proc); + process->timeout_node = list_insert_after(sleep_queue, before, proc); + spin_unlock(sleep_lock); + IRQ_RES; + } else { + process->timeout_node = NULL; + } + + process->awoken_index = -1; + /* Wait. */ + switch_task(0); + + return process->awoken_index; +} + +int process_awaken_from_fswait(process_t * process, int index) { + process->awoken_index = index; + list_free(process->node_waits); + free(process->node_waits); + process->node_waits = NULL; + if (process->timeout_node && process->timeout_node->owner == sleep_queue) { + sleeper_t * proc = process->timeout_node->value; + if (proc->is_fswait != -1) { + list_delete(sleep_queue, process->timeout_node); + free(process->timeout_node->value); + free(process->timeout_node); + } + } + process->timeout_node = NULL; + make_process_ready(process); + return 0; +} + +int process_alert_node(process_t * process, void * value) { + + if (!is_valid_process(process)) { + debug_print(WARNING, "Invalid process in alert from fswait."); + return 0; + } + + + + if (!process->node_waits) { + return 0; /* Possibly already returned. Wait for another call. */ + } + + int index = 0; + foreach(node, process->node_waits) { + if (value == node->value) { + return process_awaken_from_fswait(process, index); + } + index++; + } + + return -1; +} + diff --git a/kernel/sys/signal.c b/kernel/sys/signal.c new file mode 100644 index 00000000..3c39fe5e --- /dev/null +++ b/kernel/sys/signal.c @@ -0,0 +1,227 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2012-2014 Kevin Lange + * + * Signal Handling + */ + +#include +#include +#include + +void enter_signal_handler(uintptr_t location, int signum, uintptr_t stack) { + IRQ_OFF; + asm volatile( + "mov %2, %%esp\n" + "pushl %1\n" /* argument count */ + "pushl $" STRSTR(SIGNAL_RETURN) "\n" + "mov $0x23, %%ax\n" /* Segment selector */ + "mov %%ax, %%ds\n" + "mov %%ax, %%es\n" + "mov %%ax, %%fs\n" + "mov %%ax, %%gs\n" + "mov %%esp, %%eax\n" /* Stack -> EAX */ + "pushl $0x23\n" /* Segment selector again */ + "pushl %%eax\n" + "pushf\n" /* Push flags */ + "popl %%eax\n" /* Fix the Interrupt flag */ + "orl $0x200, %%eax\n" + "pushl %%eax\n" + "pushl $0x1B\n" + "pushl %0\n" /* Push the entry point */ + "iret\n" + : : "m"(location), "m"(signum), "r"(stack) : "%ax", "%esp", "%eax"); + + debug_print(CRITICAL, "Failed to jump to signal handler!"); +} + +static spin_lock_t sig_lock; +static spin_lock_t sig_lock_b; + +char isdeadly[] = { + 0, /* 0? */ + 1, /* SIGHUP */ + 1, /* SIGINT */ + 2, /* SIGQUIT */ + 2, /* SIGILL */ + 2, /* SIGTRAP */ + 2, /* SIGABRT */ + 2, /* SIGEMT */ + 2, /* SIGFPE */ + 1, /* SIGKILL */ + 2, /* SIGBUS */ + 2, /* SIGSEGV */ + 2, /* SIGSYS */ + 1, /* SIGPIPE */ + 1, /* SIGALRM */ + 1, /* SIGTERM */ + 1, /* SIGUSR1 */ + 1, /* SIGUSR2 */ + 0, /* SIGCHLD */ + 0, /* SIGPWR */ + 0, /* SIGWINCH */ + 0, /* SIGURG */ + 0, /* SIGPOLL */ + 3, /* SIGSTOP */ + 3, /* SIGTSTP */ + 0, /* SIGCONT */ + 3, /* SIGTTIN */ + 3, /* SIGTTOUT */ + 1, /* SIGVTALRM */ + 1, /* SIGPROF */ + 2, /* SIGXCPU */ + 2, /* SIGXFSZ */ + 0, /* SIGWAITING */ + 1, /* SIGDIAF */ + 0, /* SIGHATE */ + 0, /* SIGWINEVENT*/ + 0, /* SIGCAT */ +}; + +void handle_signal(process_t * proc, signal_t * sig) { + uintptr_t handler = sig->handler; + uintptr_t signum = sig->signum; + free(sig); + + if (proc->finished) { + return; + } + + if (signum == 0 || signum >= NUMSIGNALS) { + /* Ignore */ + return; + } + + if (!handler) { + char dowhat = isdeadly[signum]; + if (dowhat == 1 || dowhat == 2) { + debug_print(WARNING, "Process %d killed by unhandled signal (%d)", proc->id, signum); + kexit(128 + signum); + __builtin_unreachable(); + } else { + debug_print(WARNING, "Ignoring signal %d by default in pid %d", signum, proc->id); + } + /* XXX dowhat == 2: should dump core */ + /* XXX dowhat == 3: stop */ + return; + } + + if (handler == 1) /* Ignore */ { + return; + } + + debug_print(NOTICE, "handling signal in process %d (%d)", proc->id, signum); + + uintptr_t stack = 0xFFFF0000; + if (proc->syscall_registers->useresp < 0x10000100) { + stack = proc->image.user_stack; + } else { + stack = proc->syscall_registers->useresp; + } + + /* Not marked as ignored, must call signal */ + enter_signal_handler(handler, signum, stack); + +} + +list_t * rets_from_sig; + +void return_from_signal_handler(void) { +#if 0 + debug_print(INFO, "Return From Signal for process %d", current_process->id); +#endif + + if (__builtin_expect(!rets_from_sig, 0)) { + rets_from_sig = list_create(); + } + + spin_lock(sig_lock); + list_insert(rets_from_sig, (process_t *)current_process); + spin_unlock(sig_lock); + + switch_next(); +} + +void fix_signal_stacks(void) { + uint8_t redo_me = 0; + if (rets_from_sig) { + spin_lock(sig_lock_b); + while (rets_from_sig->head) { + spin_lock(sig_lock); + node_t * n = list_dequeue(rets_from_sig); + spin_unlock(sig_lock); + if (!n) { + continue; + } + process_t * p = n->value; + free(n); + if (p == current_process) { + redo_me = 1; + continue; + } + p->thread.esp = p->signal_state.esp; + p->thread.eip = p->signal_state.eip; + p->thread.ebp = p->signal_state.ebp; + memcpy((void *)(p->image.stack - KERNEL_STACK_SIZE), p->signal_kstack, KERNEL_STACK_SIZE); + free(p->signal_kstack); + p->signal_kstack = NULL; + make_process_ready(p); + } + spin_unlock(sig_lock_b); + } + if (redo_me) { + spin_lock(sig_lock); + list_insert(rets_from_sig, (process_t *)current_process); + spin_unlock(sig_lock); + switch_next(); + } +} + +int send_signal(pid_t process, uint32_t signal) { + process_t * receiver = process_from_pid(process); + + if (!receiver) { + /* Invalid pid */ + return 1; + } + + if (receiver->user != current_process->user && current_process->user != USER_ROOT_UID) { + /* No way in hell. */ + return 1; + } + + if (signal > NUMSIGNALS) { + /* Invalid signal */ + return 1; + } + + if (receiver->finished) { + /* Can't send signals to finished processes */ + return 1; + } + + if (!receiver->signals.functions[signal] && !isdeadly[signal]) { + /* If we're blocking a signal and it's not going to kill us, don't deliver it */ + return 1; + } + + /* Append signal to list */ + signal_t * sig = malloc(sizeof(signal_t)); + sig->handler = (uintptr_t)receiver->signals.functions[signal]; + sig->signum = signal; + memset(&sig->registers_before, 0x00, sizeof(regs_t)); + + if (receiver->node_waits) { + process_awaken_from_fswait(receiver, -1); + } + + if (!process_is_ready(receiver)) { + make_process_ready(receiver); + } + + list_insert(receiver->signal_queue, sig); + + return 0; +} + diff --git a/kernel/sys/syscall.c b/kernel/sys/syscall.c new file mode 100644 index 00000000..b5e24e8b --- /dev/null +++ b/kernel/sys/syscall.c @@ -0,0 +1,975 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2012 Markus Schober + * + * Syscall Tables + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char hostname[256]; +static size_t hostname_len = 0; + +#define FD_INRANGE(FD) \ + ((FD) < (int)current_process->fds->length && (FD) >= 0) +#define FD_ENTRY(FD) \ + (current_process->fds->entries[(FD)]) +#define FD_CHECK(FD) \ + (FD_INRANGE(FD) && FD_ENTRY(FD)) + +#define PTR_INRANGE(PTR) \ + ((uintptr_t)(PTR) > current_process->image.entry) +#define PTR_VALIDATE(PTR) \ + ptr_validate((void *)(PTR), __func__) + +static void ptr_validate(void * ptr, const char * syscall) { + if (ptr && !PTR_INRANGE(ptr)) { + debug_print(ERROR, "SEGFAULT: invalid pointer passed to %s. (0x%x < 0x%x)", + syscall, (uintptr_t)ptr, current_process->image.entry); + HALT_AND_CATCH_FIRE("Segmentation fault", NULL); + } +} + +void validate(void * ptr) { + ptr_validate(ptr, "syscall"); +} + +/* + * Exit the current task. + * DOES NOT RETURN! + */ +static int __attribute__((noreturn)) sys_exit(int retval) { + /* Deschedule the current task */ + task_exit(retval); + for (;;) ; +} + +static int sys_read(int fd, char * ptr, int len) { + if (FD_CHECK(fd)) { + PTR_VALIDATE(ptr); + + fs_node_t * node = FD_ENTRY(fd); + uint32_t out = read_fs(node, node->offset, len, (uint8_t *)ptr); + node->offset += out; + return (int)out; + } + return -1; +} + +static int sys_ioctl(int fd, int request, void * argp) { + if (FD_CHECK(fd)) { + PTR_VALIDATE(argp); + return ioctl_fs(FD_ENTRY(fd), request, argp); + } + return -1; +} + +static int sys_readdir(int fd, int index, struct dirent * entry) { + if (FD_CHECK(fd)) { + PTR_VALIDATE(entry); + struct dirent * kentry = readdir_fs(FD_ENTRY(fd), (uint32_t)index); + if (kentry) { + memcpy(entry, kentry, sizeof *entry); + free(kentry); + return 0; + } else { + return 1; + } + } + return -1; +} + +static int sys_write(int fd, char * ptr, int len) { + if (FD_CHECK(fd)) { + PTR_VALIDATE(ptr); + fs_node_t * node = FD_ENTRY(fd); + if (!has_permission(node, 02)) { + debug_print(WARNING, "access denied (write, fd=%d)", fd); + return -EACCES; + } + uint32_t out = write_fs(node, node->offset, len, (uint8_t *)ptr); + node->offset += out; + return out; + } + return -1; +} + +static int sys_waitpid(int pid, int * status, int options) { + if (status && !PTR_INRANGE(status)) { + return -EINVAL; + } + return waitpid(pid, status, options); +} + +static int sys_open(const char * file, int flags, int mode) { + PTR_VALIDATE(file); + debug_print(NOTICE, "open(%s) flags=0x%x; mode=0x%x", file, flags, mode); + fs_node_t * node = kopen((char *)file, flags); + + if (node && !has_permission(node, 04)) { + debug_print(WARNING, "access denied (read, sys_open, file=%s)", file); + return -EACCES; + } + if (node && ((flags & O_RDWR) || (flags & O_APPEND) || (flags & O_WRONLY))) { + if (!has_permission(node, 02)) { + debug_print(WARNING, "access denied (write, sys_open, file=%s)", file); + return -EACCES; + } + } + + if (!node && (flags & O_CREAT)) { + /* TODO check directory permissions */ + debug_print(NOTICE, "- file does not exist and create was requested."); + /* Um, make one */ + int result = create_file_fs((char *)file, mode); + if (!result) { + node = kopen((char *)file, flags); + } else { + return result; + } + } + if (!node) { + debug_print(NOTICE, "File does not exist; someone should be setting errno?"); + return -1; + } + node->offset = 0; + int fd = process_append_fd((process_t *)current_process, node); + debug_print(INFO, "[open] pid=%d %s -> %d", getpid(), file, fd); + return fd; +} + +static int sys_access(const char * file, int flags) { + PTR_VALIDATE(file); + debug_print(INFO, "access(%s, 0x%x) from pid=%d", file, flags, getpid()); + fs_node_t * node = kopen((char *)file, 0); + if (!node) return -1; + close_fs(node); + return 0; +} + +static int sys_close(int fd) { + if (FD_CHECK(fd)) { + close_fs(FD_ENTRY(fd)); + FD_ENTRY(fd) = NULL; + return 0; + } + return -1; +} + +static int sys_sbrk(int size) { + process_t * proc = (process_t *)current_process; + if (proc->group != 0) { + proc = process_from_pid(proc->group); + } + spin_lock(proc->image.lock); + uintptr_t ret = proc->image.heap; + uintptr_t i_ret = ret; + ret = (ret + 0xfff) & ~0xfff; /* Rounds ret to 0x1000 in O(1) */ + proc->image.heap += (ret - i_ret) + size; + while (proc->image.heap > proc->image.heap_actual) { + proc->image.heap_actual += 0x1000; + assert(proc->image.heap_actual % 0x1000 == 0); + alloc_frame(get_page(proc->image.heap_actual, 1, current_directory), 0, 1); + invalidate_tables_at(proc->image.heap_actual); + } + spin_unlock(proc->image.lock); + return ret; +} + +static int sys_getpid(void) { + /* The user actually wants the pid of the originating thread (which can be us). */ + if (current_process->group) { + return current_process->group; + } else { + /* We are the leader */ + return current_process->id; + } +} + +/* Actual getpid() */ +static int sys_gettid(void) { + return getpid(); +} + +static int sys_execve(const char * filename, char *const argv[], char *const envp[]) { + PTR_VALIDATE(argv); + PTR_VALIDATE(filename); + PTR_VALIDATE(envp); + + debug_print(NOTICE, "%d = exec(%s, ...)", current_process->id, filename); + + int argc = 0; + int envc = 0; + while (argv[argc]) { + PTR_VALIDATE(argv[argc]); + ++argc; + } + + if (envp) { + while (envp[envc]) { + PTR_VALIDATE(envp[envc]); + ++envc; + } + } + + debug_print(INFO, "Allocating space for arguments..."); + char ** argv_ = malloc(sizeof(char *) * (argc + 1)); + for (int j = 0; j < argc; ++j) { + argv_[j] = malloc((strlen(argv[j]) + 1) * sizeof(char)); + memcpy(argv_[j], argv[j], strlen(argv[j]) + 1); + } + argv_[argc] = 0; + char ** envp_; + if (envp && envc) { + envp_ = malloc(sizeof(char *) * (envc + 1)); + for (int j = 0; j < envc; ++j) { + envp_[j] = malloc((strlen(envp[j]) + 1) * sizeof(char)); + memcpy(envp_[j], envp[j], strlen(envp[j]) + 1); + } + envp_[envc] = 0; + } else { + envp_ = malloc(sizeof(char *)); + envp_[0] = NULL; + } + debug_print(INFO,"Releasing all shmem regions..."); + shm_release_all((process_t *)current_process); + + current_process->cmdline = argv_; + + debug_print(INFO,"Executing..."); + /* Discard envp */ + exec((char *)filename, argc, (char **)argv_, (char **)envp_); + return -1; +} + +static int sys_seek(int fd, int offset, int whence) { + if (FD_CHECK(fd)) { + if (fd < 3) { + return 0; + } + switch (whence) { + case 0: + FD_ENTRY(fd)->offset = offset; + break; + case 1: + FD_ENTRY(fd)->offset += offset; + break; + case 2: + FD_ENTRY(fd)->offset = FD_ENTRY(fd)->length + offset; + break; + } + return FD_ENTRY(fd)->offset; + } + return -1; +} + +static int stat_node(fs_node_t * fn, uintptr_t st) { + struct stat * f = (struct stat *)st; + + PTR_VALIDATE(f); + + if (!fn) { + memset(f, 0x00, sizeof(struct stat)); + debug_print(INFO, "stat: This file doesn't exist"); + return -1; + } + f->st_dev = (uint16_t)(((uint32_t)fn->device & 0xFFFF0) >> 8); + f->st_ino = fn->inode; + + uint32_t flags = 0; + if (fn->flags & FS_FILE) { flags |= _IFREG; } + if (fn->flags & FS_DIRECTORY) { flags |= _IFDIR; } + if (fn->flags & FS_CHARDEVICE) { flags |= _IFCHR; } + if (fn->flags & FS_BLOCKDEVICE) { flags |= _IFBLK; } + if (fn->flags & FS_PIPE) { flags |= _IFIFO; } + if (fn->flags & FS_SYMLINK) { flags |= _IFLNK; } + + f->st_mode = fn->mask | flags; + f->st_nlink = fn->nlink; + f->st_uid = fn->uid; + f->st_gid = fn->gid; + f->st_rdev = 0; + f->st_size = fn->length; + + f->st_atime = fn->atime; + f->st_mtime = fn->mtime; + f->st_ctime = fn->ctime; + f->st_blksize = 512; /* whatever */ + + if (fn->get_size) { + f->st_size = fn->get_size(fn); + } + + return 0; +} + +static int sys_statf(char * file, uintptr_t st) { + int result; + PTR_VALIDATE(file); + PTR_VALIDATE(st); + fs_node_t * fn = kopen(file, 0); + result = stat_node(fn, st); + if (fn) { + close_fs(fn); + } + return result; +} + +static int sys_chmod(char * file, int mode) { + int result; + PTR_VALIDATE(file); + fs_node_t * fn = kopen(file, 0); + if (fn) { + result = chmod_fs(fn, mode); + close_fs(fn); + return result; + } else { + return -1; + } +} + +static int sys_chown(char * file, int uid, int gid) { + int result; + PTR_VALIDATE(file); + fs_node_t * fn = kopen(file, 0); + if (fn) { + result = chown_fs(fn, uid, gid); + close_fs(fn); + return result; + } else { + return -1; + } +} + + +static int sys_stat(int fd, uintptr_t st) { + PTR_VALIDATE(st); + if (FD_CHECK(fd)) { + return stat_node(FD_ENTRY(fd), st); + } + return -1; +} + +static int sys_mkpipe(void) { + fs_node_t * node = make_pipe(4096 * 2); + open_fs(node, 0); + return process_append_fd((process_t *)current_process, node); +} + +static int sys_dup2(int old, int new) { + return process_move_fd((process_t *)current_process, old, new); +} + +static int sys_getuid(void) { + return current_process->user; +} + +static int sys_setuid(user_t new_uid) { + if (current_process->user == USER_ROOT_UID) { + current_process->user = new_uid; + return 0; + } + return -1; +} + +static int sys_uname(struct utsname * name) { + PTR_VALIDATE(name); + char version_number[256]; + sprintf(version_number, __kernel_version_format, + __kernel_version_major, + __kernel_version_minor, + __kernel_version_lower, + __kernel_version_suffix); + char version_string[256]; + sprintf(version_string, "%s %s %s", + __kernel_version_codename, + __kernel_build_date, + __kernel_build_time); + strcpy(name->sysname, __kernel_name); + strcpy(name->nodename, hostname); + strcpy(name->release, version_number); + strcpy(name->version, version_string); + strcpy(name->machine, __kernel_arch); + strcpy(name->domainname, ""); + return 0; +} + +static int sys_signal(uint32_t signum, uintptr_t handler) { + if (signum > NUMSIGNALS) { + return -1; + } + uintptr_t old = current_process->signals.functions[signum]; + current_process->signals.functions[signum] = handler; + return (int)old; +} + +/* +static void inspect_memory (uintptr_t vaddr) { + // Please use this scary hack of a function as infrequently as possible. + shmem_debug_frame(vaddr); +} +*/ + +static int sys_reboot(void) { + debug_print(NOTICE, "[kernel] Reboot requested from process %d by user #%d", current_process->id, current_process->user); + if (current_process->user != USER_ROOT_UID) { + return -1; + } else { + debug_print(NOTICE, "[kernel] Good bye!"); + /* Goodbye, cruel world */ + IRQ_OFF; + uint8_t out = 0x02; + while ((out & 0x02) != 0) { + out = inportb(0x64); + } + outportb(0x64, 0xFE); /* Reset */ + STOP; + } + return 0; +} + +static int sys_chdir(char * newdir) { + PTR_VALIDATE(newdir); + char * path = canonicalize_path(current_process->wd_name, newdir); + fs_node_t * chd = kopen(path, 0); + if (chd) { + if ((chd->flags & FS_DIRECTORY) == 0) { + close_fs(chd); + return -1; + } + close_fs(chd); + free(current_process->wd_name); + current_process->wd_name = malloc(strlen(path) + 1); + memcpy(current_process->wd_name, path, strlen(path) + 1); + return 0; + } else { + return -1; + } +} + +static int sys_getcwd(char * buf, size_t size) { + if (buf) { + PTR_VALIDATE(buf); + size_t len = strlen(current_process->wd_name) + 1; + return (int)memcpy(buf, current_process->wd_name, MIN(size, len)); + } + return 0; +} + +static int sys_sethostname(char * new_hostname) { + if (current_process->user == USER_ROOT_UID) { + PTR_VALIDATE(new_hostname); + size_t len = strlen(new_hostname) + 1; + if (len > 256) { + return 1; + } + hostname_len = len; + memcpy(hostname, new_hostname, hostname_len); + return 0; + } else { + return 1; + } +} + +static int sys_gethostname(char * buffer) { + PTR_VALIDATE(buffer); + memcpy(buffer, hostname, hostname_len); + return hostname_len; +} + +extern int mkdir_fs(char *name, uint16_t permission); + +static int sys_mkdir(char * path, uint32_t mode) { + return mkdir_fs(path, 0777); +} + +/* + * Yield the rest of the quantum; + * useful for busy waiting and other such things + */ +static int sys_yield(void) { + switch_task(1); + return 1; +} + +/* + * System Function + */ +static int sys_sysfunc(int fn, char ** args) { + /* System Functions are special debugging system calls */ + if (current_process->user == USER_ROOT_UID) { + switch (fn) { + case 3: + debug_print(ERROR, "sync is currently unimplemented"); + //ext2_disk_sync(); + return 0; + case 4: + /* Request kernel output to file descriptor in arg0*/ + debug_print(NOTICE, "Setting output to file object in process %d's fd=%d!", getpid(), (int)args); + debug_file = current_process->fds->entries[(int)args]; + break; + case 5: + { + char *arg; + PTR_VALIDATE(args); + for (arg = args[0]; arg; arg++) + PTR_VALIDATE(arg); + debug_print(NOTICE, "Replacing process %d's file descriptors with pointers to %s", getpid(), (char *)args); + fs_node_t * repdev = kopen((char *)args, 0); + while (current_process->fds->length < 3) { + process_append_fd((process_t *)current_process, repdev); + } + FD_ENTRY(0) = repdev; + FD_ENTRY(1) = repdev; + FD_ENTRY(2) = repdev; + } + break; + case 6: + debug_print(WARNING, "writing contents of file %s to sdb", args[0]); + { + PTR_VALIDATE(args); + PTR_VALIDATE(args[0]); + fs_node_t * file = kopen((char *)args[0], 0); + if (!file) { + return -1; + } + size_t length = file->length; + uint8_t * buffer = malloc(length); + read_fs(file, 0, length, (uint8_t *)buffer); + close_fs(file); + debug_print(WARNING, "Finished reading file, going to write it now."); + + fs_node_t * f = kopen("/dev/sdb", 0); + if (!f) { + return 1; + } + + write_fs(f, 0, length, buffer); + + free(buffer); + return 0; + } + case 7: + debug_print(NOTICE, "Spawning debug hook as child of process %d.", getpid()); + if (debug_hook) { + fs_node_t * tty = FD_ENTRY(0); + return create_kernel_tasklet(debug_hook, "[kttydebug]", tty); + } else { + return -1; + } + case 8: + debug_print(NOTICE, "Loading module %s.", args[0]); + { + /* Check file existence */ + fs_node_t * file = kopen(args[0], 0); + if (!file) { + return 1; + } + close_fs(file); + + module_data_t * mod_info = module_load(args[0]); + if (!mod_info) { + return 2; + } + return 0; + } + } + } + switch (fn) { + /* The following functions are here to support the loader and are probably bad. */ + case 9: + { + process_t * proc = (process_t *)current_process; + if (proc->group != 0) { + proc = process_from_pid(proc->group); + } + spin_lock(proc->image.lock); + /* Set new heap start */ + proc->image.heap = (uintptr_t)args[0]; + proc->image.heap_actual = proc->image.heap & 0xFFFFF000; + assert(proc->image.heap_actual % 0x1000 == 0); + alloc_frame(get_page(proc->image.heap_actual, 1, current_directory), 0, 1); + invalidate_tables_at(proc->image.heap_actual); + while (proc->image.heap > proc->image.heap_actual) { + proc->image.heap_actual += 0x1000; + alloc_frame(get_page(proc->image.heap_actual, 1, current_directory), 0, 1); + invalidate_tables_at(proc->image.heap_actual); + } + spin_unlock(proc->image.lock); + return 0; + } + case 10: + { + /* Load pages to fit region. */ + uintptr_t address = (uintptr_t)args[0]; + size_t size = (size_t)args[1]; + /* TODO: Other arguments for read/write? */ + + if (address & 0xFFF) { + size += address & 0xFFF; + address &= 0xFFFFF000; + } + + process_t * proc = (process_t *)current_process; + if (proc->group != 0) { + proc = process_from_pid(proc->group); + } + + spin_lock(proc->image.lock); + for (size_t x = 0; x < size; x += 0x1000) { + alloc_frame(get_page(address + x, 1, current_directory), 0, 1); + invalidate_tables_at(address + x); + } + spin_unlock(proc->image.lock); + + return 0; + } + + case 11: + { + /* Set command line (meant for threads to set descriptions) */ + int count = 0; + char **arg = args; + PTR_VALIDATE(args); + while (*arg) { + PTR_VALIDATE(*args); + count++; + arg++; + } + /* + * XXX We have a pretty obvious leak in storing command lines, since + * we never free them! Unfortunately, at the moment, they are + * shared between different processes, so until that gets fixed + * we're going to be just as bad as the rest of the codebase and + * just not free the previous value. + */ + current_process->cmdline = malloc(sizeof(char*)*(count+1)); + int i = 0; + while (i < count) { + current_process->cmdline[i] = strdup(args[i]); + i++; + } + current_process->cmdline[i] = NULL; + return 0; + } + + case 12: + /* + * Print a debug message to the kernel console + * XXX: This probably should be a thing normal users can do. + */ + PTR_VALIDATE(args); + debug_print(WARNING, "0x%x 0x%x 0x%x 0x%x", args[0], args[1], args[2], args[3]); + _debug_print(args[0], (uintptr_t)args[1], (uint32_t)args[2], args[3] ? args[3] : "(null)"); + return 0; + break; + + case 13: + /* + * Set VGA text-mode cursor location + * (Not actually used to place a cursor, we use this to move the cursor off screen) + */ + PTR_VALIDATE(args); + outportb(0x3D4, 14); + outportb(0x3D5, (unsigned int)args[0]); + outportb(0x3D4, 15); + outportb(0x3D5, (unsigned int)args[1]); + + return 0; + + default: + debug_print(ERROR, "Bad system function %d", fn); + break; + } + return -1; /* Bad system function or access failure */ +} + +static int sys_sleepabs(unsigned long seconds, unsigned long subseconds) { + /* Mark us as asleep until */ + sleep_until((process_t *)current_process, seconds, subseconds); + + /* Switch without adding us to the queue */ + switch_task(0); + + if (seconds > timer_ticks || (seconds == timer_ticks && subseconds >= timer_subticks)) { + return 0; + } else { + return 1; + } +} + +static int sys_sleep(unsigned long seconds, unsigned long subseconds) { + unsigned long s, ss; + relative_time(seconds, subseconds * 10, &s, &ss); + return sys_sleepabs(s, ss); +} + +static int sys_umask(int mode) { + current_process->mask = mode & 0777; + return 0; +} + +static int sys_unlink(char * file) { + PTR_VALIDATE(file); + return unlink_fs(file); +} + +static int sys_fork(void) { + return (int)fork(); +} + +static int sys_clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg) { + if (!new_stack || !PTR_INRANGE(new_stack)) return -1; + if (!thread_func || !PTR_INRANGE(thread_func)) return -1; + return (int)clone(new_stack, thread_func, arg); +} + +static int sys_shm_obtain(char * path, size_t * size) { + PTR_VALIDATE(path); + PTR_VALIDATE(size); + + return (int)shm_obtain(path, size); +} + +static int sys_shm_release(char * path) { + PTR_VALIDATE(path); + + return shm_release(path); +} + +static int sys_kill(pid_t process, uint32_t signal) { + return send_signal(process, signal); +} + +static int sys_gettimeofday(struct timeval * tv, void * tz) { + PTR_VALIDATE(tv); + PTR_VALIDATE(tz); + + return gettimeofday(tv, tz); +} + +static int sys_openpty(int * master, int * slave, char * name, void * _ign0, void * size) { + /* We require a place to put these when we are done. */ + if (!master || !slave) return -1; + if (master && !PTR_INRANGE(master)) return -1; + if (slave && !PTR_INRANGE(slave)) return -1; + if (size && !PTR_INRANGE(size)) return -1; + + /* Create a new pseudo terminal */ + fs_node_t * fs_master; + fs_node_t * fs_slave; + + pty_create(size, &fs_master, &fs_slave); + + /* Append the master and slave to the calling process */ + *master = process_append_fd((process_t *)current_process, fs_master); + *slave = process_append_fd((process_t *)current_process, fs_slave); + + open_fs(fs_master, 0); + open_fs(fs_slave, 0); + + /* Return success */ + return 0; +} + +static int sys_pipe(int pipes[2]) { + if (pipes && !PTR_INRANGE(pipes)) { + return -EFAULT; + } + + fs_node_t * outpipes[2]; + + make_unix_pipe(outpipes); + + open_fs(outpipes[0], 0); + open_fs(outpipes[1], 0); + + pipes[0] = process_append_fd((process_t *)current_process, outpipes[0]); + pipes[1] = process_append_fd((process_t *)current_process, outpipes[1]); + return 0; +} + +static int sys_mount(char * arg, char * mountpoint, char * type, unsigned long flags, void * data) { + /* TODO: Make use of flags and data from mount command. */ + (void)flags; + (void)data; + + if (current_process->user != USER_ROOT_UID) { + return -EPERM; + } + + if (PTR_INRANGE(arg) && PTR_INRANGE(mountpoint) && PTR_INRANGE(type)) { + return vfs_mount_type(type, arg, mountpoint); + } + + return -EFAULT; +} + +static int sys_symlink(char * target, char * name) { + PTR_VALIDATE(target); + PTR_VALIDATE(name); + return symlink_fs(target, name); +} + +static int sys_readlink(const char * file, char * ptr, int len) { + PTR_VALIDATE(file); + fs_node_t * node = kopen((char *) file, O_PATH | O_NOFOLLOW); + if (!node) { + return -ENOENT; + } + int rv = readlink_fs(node, ptr, len); + close_fs(node); + return rv; +} + +static int sys_lstat(char * file, uintptr_t st) { + int result; + PTR_VALIDATE(file); + PTR_VALIDATE(st); + fs_node_t * fn = kopen(file, O_PATH | O_NOFOLLOW); + result = stat_node(fn, st); + if (fn) { + close_fs(fn); + } + return result; +} + +static int sys_fswait(int c, int fds[]) { + PTR_VALIDATE(fds); + for (int i = 0; i < c; ++i) { + if (!FD_CHECK(fds[i])) return -1; + } + fs_node_t ** nodes = malloc(sizeof(fs_node_t *)*(c+1)); + for (int i = 0; i < c; ++i) { + nodes[i] = FD_ENTRY(fds[i]); + } + nodes[c] = NULL; + + int result = process_wait_nodes((process_t *)current_process, nodes, -1); + free(nodes); + return result; +} + +static int sys_fswait_timeout(int c, int fds[], int timeout) { + PTR_VALIDATE(fds); + for (int i = 0; i < c; ++i) { + if (!FD_CHECK(fds[i])) return -1; + } + fs_node_t ** nodes = malloc(sizeof(fs_node_t *)*(c+1)); + for (int i = 0; i < c; ++i) { + nodes[i] = FD_ENTRY(fds[i]); + } + nodes[c] = NULL; + + int result = process_wait_nodes((process_t *)current_process, nodes, timeout); + free(nodes); + return result; +} + +/* + * System Call Internals + */ +static int (*syscalls[])() = { + /* System Call Table */ + [SYS_EXT] = sys_exit, + [SYS_OPEN] = sys_open, + [SYS_READ] = sys_read, + [SYS_WRITE] = sys_write, + [SYS_CLOSE] = sys_close, + [SYS_GETTIMEOFDAY] = sys_gettimeofday, + [SYS_EXECVE] = sys_execve, + [SYS_FORK] = sys_fork, + [SYS_GETPID] = sys_getpid, + [SYS_SBRK] = sys_sbrk, + [SYS_UNAME] = sys_uname, + [SYS_OPENPTY] = sys_openpty, + [SYS_SEEK] = sys_seek, + [SYS_STAT] = sys_stat, + [SYS_MKPIPE] = sys_mkpipe, + [SYS_DUP2] = sys_dup2, + [SYS_GETUID] = sys_getuid, + [SYS_SETUID] = sys_setuid, + [SYS_REBOOT] = sys_reboot, + [SYS_READDIR] = sys_readdir, + [SYS_CHDIR] = sys_chdir, + [SYS_GETCWD] = sys_getcwd, + [SYS_CLONE] = sys_clone, + [SYS_SETHOSTNAME] = sys_sethostname, + [SYS_GETHOSTNAME] = sys_gethostname, + [SYS_MKDIR] = sys_mkdir, + [SYS_SHM_OBTAIN] = sys_shm_obtain, + [SYS_SHM_RELEASE] = sys_shm_release, + [SYS_KILL] = sys_kill, + [SYS_SIGNAL] = sys_signal, + [SYS_GETTID] = sys_gettid, + [SYS_YIELD] = sys_yield, + [SYS_SYSFUNC] = sys_sysfunc, + [SYS_SLEEPABS] = sys_sleepabs, + [SYS_SLEEP] = sys_sleep, + [SYS_IOCTL] = sys_ioctl, + [SYS_ACCESS] = sys_access, + [SYS_STATF] = sys_statf, + [SYS_CHMOD] = sys_chmod, + [SYS_UMASK] = sys_umask, + [SYS_UNLINK] = sys_unlink, + [SYS_WAITPID] = sys_waitpid, + [SYS_PIPE] = sys_pipe, + [SYS_MOUNT] = sys_mount, + [SYS_SYMLINK] = sys_symlink, + [SYS_READLINK] = sys_readlink, + [SYS_LSTAT] = sys_lstat, + [SYS_FSWAIT] = sys_fswait, + [SYS_FSWAIT2] = sys_fswait_timeout, + [SYS_CHOWN] = sys_chown, +}; + +uint32_t num_syscalls = sizeof(syscalls) / sizeof(*syscalls); + +typedef uint32_t (*scall_func)(unsigned int, ...); + +pid_t trace_pid = 0; + +void syscall_handler(struct regs * r) { + if (r->eax >= num_syscalls) { + return; + } + + uintptr_t location = (uintptr_t)syscalls[r->eax]; + if (!location) { + return; + } + + /* Update the syscall registers for this process */ + current_process->syscall_registers = r; + + if (trace_pid && current_process->id == trace_pid) { + debug_print(WARNING, "[syscall trace] %d (0x%x) 0x%x 0x%x 0x%x 0x%x 0x%x", r->eax, location, r->ebx, r->ecx, r->edx, r->esi, r->edi); + } + + /* Call the syscall function */ + scall_func func = (scall_func)location; + uint32_t ret = func(r->ebx, r->ecx, r->edx, r->esi, r->edi); + + if ((current_process->syscall_registers == r) || + (location != (uintptr_t)&fork && location != (uintptr_t)&clone)) { + r->eax = ret; + } +} + +void syscalls_install(void) { + debug_print(NOTICE, "Initializing syscall table with %d functions", num_syscalls); + isrs_install_handler(0x7F, &syscall_handler); +} + diff --git a/kernel/sys/system.c b/kernel/sys/system.c new file mode 100644 index 00000000..124deeef --- /dev/null +++ b/kernel/sys/system.c @@ -0,0 +1,88 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2013 Kevin Lange + * + * System Functions + * + */ +#include + +char * boot_arg = NULL; +char * boot_arg_extra = NULL; + +/* + * memsetw + * Set `count` shorts to `val`. + */ +unsigned short * memsetw(unsigned short * dest, unsigned short val, int count) { + int i = 0; + for ( ; i < count; ++i ) { + dest[i] = val; + } + return dest; +} + +uint32_t __attribute__ ((pure)) krand(void) { + static uint32_t x = 123456789; + static uint32_t y = 362436069; + static uint32_t z = 521288629; + static uint32_t w = 88675123; + + uint32_t t; + + t = x ^ (x << 11); + x = y; y = z; z = w; + return w = w ^ (w >> 19) ^ t ^ (t >> 8); +} + +unsigned short inports(unsigned short _port) { + unsigned short rv; + asm volatile ("inw %1, %0" : "=a" (rv) : "dN" (_port)); + return rv; +} + +void outports(unsigned short _port, unsigned short _data) { + asm volatile ("outw %1, %0" : : "dN" (_port), "a" (_data)); +} + +unsigned int inportl(unsigned short _port) { + unsigned int rv; + asm volatile ("inl %%dx, %%eax" : "=a" (rv) : "dN" (_port)); + return rv; +} + +void outportl(unsigned short _port, unsigned int _data) { + asm volatile ("outl %%eax, %%dx" : : "dN" (_port), "a" (_data)); +} + +unsigned char inportb(unsigned short _port) { + unsigned char rv; + asm volatile ("inb %1, %0" : "=a" (rv) : "dN" (_port)); + return rv; +} + +void outportb(unsigned short _port, unsigned char _data) { + asm volatile ("outb %1, %0" : : "dN" (_port), "a" (_data)); +} + +void outportsm(unsigned short port, unsigned char * data, unsigned long size) { + asm volatile ("rep outsw" : "+S" (data), "+c" (size) : "d" (port)); +} + +void inportsm(unsigned short port, unsigned char * data, unsigned long size) { + asm volatile ("rep insw" : "+D" (data), "+c" (size) : "d" (port) : "memory"); +} + +size_t lfind(const char * str, const char accept) { + return (size_t)strchr(str, accept); +} + +size_t rfind(const char * str, const char accept) { + return (size_t)strrchr(str, accept); +} + +uint8_t startswith(const char * str, const char * accept) { + return strstr(str, accept) == str; +} + diff --git a/kernel/sys/task.c b/kernel/sys/task.c new file mode 100644 index 00000000..d3599306 --- /dev/null +++ b/kernel/sys/task.c @@ -0,0 +1,532 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2014 Kevin Lange + * Copyright (C) 2012 Markus Schober + * + * Task Switching and Management Functions + * + */ +#include +#include +#include +#include +#include + +#define TASK_MAGIC 0xDEADBEEF + +uint32_t next_pid = 0; + +#define PUSH(stack, type, item) stack -= sizeof(type); \ + *((type *) stack) = item + +page_directory_t *kernel_directory; +page_directory_t *current_directory; + +/* + * Clone a page directory and its contents. + * (If you do not intend to clone the contents, do it yourself!) + * + * @param src Pointer to source directory to clone from. + * @return A pointer to a new directory. + */ +page_directory_t * +clone_directory( + page_directory_t * src + ) { + /* Allocate a new page directory */ + uintptr_t phys; + page_directory_t * dir = (page_directory_t *)kvmalloc_p(sizeof(page_directory_t), &phys); + /* Clear it out */ + memset(dir, 0, sizeof(page_directory_t)); + dir->ref_count = 1; + + /* And store it... */ + dir->physical_address = phys; + uint32_t i; + for (i = 0; i < 1024; ++i) { + /* Copy each table */ + if (!src->tables[i] || (uintptr_t)src->tables[i] == (uintptr_t)0xFFFFFFFF) { + continue; + } + if (kernel_directory->tables[i] == src->tables[i]) { + /* Kernel tables are simply linked together */ + dir->tables[i] = src->tables[i]; + dir->physical_tables[i] = src->physical_tables[i]; + } else { + if (i * 0x1000 * 1024 < SHM_START) { + /* User tables must be cloned */ + uintptr_t phys; + dir->tables[i] = clone_table(src->tables[i], &phys); + dir->physical_tables[i] = phys | 0x07; + } + } + } + return dir; +} + +/* + * Free a directory and its tables + */ +void release_directory(page_directory_t * dir) { + dir->ref_count--; + + if (dir->ref_count < 1) { + uint32_t i; + for (i = 0; i < 1024; ++i) { + if (!dir->tables[i] || (uintptr_t)dir->tables[i] == (uintptr_t)0xFFFFFFFF) { + continue; + } + if (kernel_directory->tables[i] != dir->tables[i]) { + if (i * 0x1000 * 1024 < SHM_START) { + for (uint32_t j = 0; j < 1024; ++j) { + if (dir->tables[i]->pages[j].frame) { + free_frame(&(dir->tables[i]->pages[j])); + } + } + } + free(dir->tables[i]); + } + } + free(dir); + } +} + +void release_directory_for_exec(page_directory_t * dir) { + uint32_t i; + /* This better be the only owner of this directory... */ + for (i = 0; i < 1024; ++i) { + if (!dir->tables[i] || (uintptr_t)dir->tables[i] == (uintptr_t)0xFFFFFFFF) { + continue; + } + if (kernel_directory->tables[i] != dir->tables[i]) { + if (i * 0x1000 * 1024 < USER_STACK_BOTTOM) { + for (uint32_t j = 0; j < 1024; ++j) { + if (dir->tables[i]->pages[j].frame) { + free_frame(&(dir->tables[i]->pages[j])); + } + } + dir->physical_tables[i] = 0; + free(dir->tables[i]); + dir->tables[i] = 0; + } + } + } +} + +extern char * default_name; + +/* + * Clone a page table + * + * @param src Pointer to a page table to clone. + * @param physAddr [out] Pointer to the physical address of the new page table + * @return A pointer to a new page table. + */ +page_table_t * +clone_table( + page_table_t * src, + uintptr_t * physAddr + ) { + /* Allocate a new page table */ + page_table_t * table = (page_table_t *)kvmalloc_p(sizeof(page_table_t), physAddr); + memset(table, 0, sizeof(page_table_t)); + uint32_t i; + for (i = 0; i < 1024; ++i) { + /* For each frame in the table... */ + if (!src->pages[i].frame) { + continue; + } + /* Allocate a new frame */ + alloc_frame(&table->pages[i], 0, 0); + /* Set the correct access bit */ + if (src->pages[i].present) table->pages[i].present = 1; + if (src->pages[i].rw) table->pages[i].rw = 1; + if (src->pages[i].user) table->pages[i].user = 1; + if (src->pages[i].writethrough) table->pages[i].writethrough = 1; + if (src->pages[i].cachedisable) table->pages[i].cachedisable = 1; + /* Copy the contents of the page from the old table to the new one */ + copy_page_physical(src->pages[i].frame * 0x1000, table->pages[i].frame * 0x1000); + } + return table; +} + +uintptr_t frozen_stack = 0; + +/* + * Install multitasking functionality. + */ +void tasking_install(void) { + IRQ_OFF; /* Disable interrupts */ + + debug_print(NOTICE, "Initializing multitasking"); + + /* Initialize the process tree */ + initialize_process_tree(); + /* Spawn the initial process */ + current_process = spawn_init(); + kernel_idle_task = spawn_kidle(); + /* Initialize the paging environment */ +#if 0 + set_process_environment((process_t *)current_process, current_directory); +#endif + /* Switch to the kernel directory */ + switch_page_directory(current_process->thread.page_directory); + + frozen_stack = (uintptr_t)valloc(KERNEL_STACK_SIZE); + + /* Reenable interrupts */ + IRQ_RES; +} + +/* + * Fork. + * + * @return To the parent: PID of the child; to the child: 0 + */ +uint32_t fork(void) { + IRQ_OFF; + + uintptr_t esp, ebp; + + current_process->syscall_registers->eax = 0; + + /* Make a pointer to the parent process (us) on the stack */ + process_t * parent = (process_t *)current_process; + assert(parent && "Forked from nothing??"); + /* Clone the current process' page directory */ + page_directory_t * directory = clone_directory(current_directory); + assert(directory && "Could not allocate a new page directory!"); + /* Spawn a new process from this one */ + debug_print(INFO,"\033[1;32mALLOC {\033[0m"); + process_t * new_proc = spawn_process(current_process, 0); + debug_print(INFO,"\033[1;32m}\033[0m"); + assert(new_proc && "Could not allocate a new process!"); + /* Set the new process' page directory to clone */ + set_process_environment(new_proc, directory); + + struct regs r; + memcpy(&r, current_process->syscall_registers, sizeof(struct regs)); + new_proc->syscall_registers = &r; + + esp = new_proc->image.stack; + ebp = esp; + + new_proc->syscall_registers->eax = 0; + + PUSH(esp, struct regs, r); + + new_proc->thread.esp = esp; + new_proc->thread.ebp = ebp; + + new_proc->is_tasklet = parent->is_tasklet; + + new_proc->thread.eip = (uintptr_t)&return_to_userspace; + + /* Add the new process to the ready queue */ + make_process_ready(new_proc); + + IRQ_RES; + + /* Return the child PID */ + return new_proc->id; +} + +int create_kernel_tasklet(tasklet_t tasklet, char * name, void * argp) { + IRQ_OFF; + + uintptr_t esp, ebp; + + if (current_process->syscall_registers) { + current_process->syscall_registers->eax = 0; + } + + page_directory_t * directory = kernel_directory; + /* Spawn a new process from this one */ + process_t * new_proc = spawn_process(current_process, 0); + assert(new_proc && "Could not allocate a new process!"); + /* Set the new process' page directory to the original process' */ + set_process_environment(new_proc, directory); + directory->ref_count++; + /* Read the instruction pointer */ + + + if (current_process->syscall_registers) { + struct regs r; + memcpy(&r, current_process->syscall_registers, sizeof(struct regs)); + new_proc->syscall_registers = &r; + } + + esp = new_proc->image.stack; + ebp = esp; + + if (current_process->syscall_registers) { + new_proc->syscall_registers->eax = 0; + } + new_proc->is_tasklet = 1; + new_proc->name = name; + + PUSH(esp, uintptr_t, (uintptr_t)name); + PUSH(esp, uintptr_t, (uintptr_t)argp); + PUSH(esp, uintptr_t, (uintptr_t)&task_exit); + + new_proc->thread.esp = esp; + new_proc->thread.ebp = ebp; + + new_proc->thread.eip = (uintptr_t)tasklet; + + /* Add the new process to the ready queue */ + make_process_ready(new_proc); + + IRQ_RES; + + /* Return the child PID */ + return new_proc->id; +} + + +/* + * clone the current thread and create a new one in the same + * memory space with the given pointer as its new stack. + */ +uint32_t +clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg) { + uintptr_t esp, ebp; + + IRQ_OFF; + + current_process->syscall_registers->eax = 0; + + /* Make a pointer to the parent process (us) on the stack */ + process_t * parent = (process_t *)current_process; + assert(parent && "Cloned from nothing??"); + page_directory_t * directory = current_directory; + /* Spawn a new process from this one */ + process_t * new_proc = spawn_process(current_process, 1); + assert(new_proc && "Could not allocate a new process!"); + /* Set the new process' page directory to the original process' */ + set_process_environment(new_proc, directory); + directory->ref_count++; + /* Read the instruction pointer */ + + struct regs r; + memcpy(&r, current_process->syscall_registers, sizeof(struct regs)); + new_proc->syscall_registers = &r; + + esp = new_proc->image.stack; + ebp = esp; + + /* Set the gid */ + if (current_process->group) { + new_proc->group = current_process->group; + } else { + /* We are the session leader */ + new_proc->group = current_process->id; + } + + new_proc->syscall_registers->ebp = new_stack; + new_proc->syscall_registers->eip = thread_func; + + /* Push arg, bogus return address onto the new thread's stack */ + PUSH(new_stack, uintptr_t, arg); + PUSH(new_stack, uintptr_t, THREAD_RETURN); + + /* Set esp, ebp, and eip for the new thread */ + new_proc->syscall_registers->esp = new_stack; + new_proc->syscall_registers->useresp = new_stack; + + PUSH(esp, struct regs, r); + + new_proc->thread.esp = esp; + new_proc->thread.ebp = ebp; + + new_proc->is_tasklet = parent->is_tasklet; + + new_proc->thread.eip = (uintptr_t)&return_to_userspace; + + /* Add the new process to the ready queue */ + make_process_ready(new_proc); + + IRQ_RES; + + /* Return the child PID */ + return new_proc->id; +} + +/* + * Get the process ID of the current process. + * + * @return The PID of the current process. + */ +uint32_t getpid(void) { + /* Fairly self-explanatory. */ + return current_process->id; +} + +/* + * Switch to the next ready task. + * + * This is called from the interrupt handler for the interval timer to + * perform standard task switching. + */ +void switch_task(uint8_t reschedule) { + if (!current_process) { + /* Tasking is not yet installed. */ + return; + } + if (!current_process->running) { + switch_next(); + } + + /* Collect the current kernel stack and instruction pointers */ + uintptr_t esp, ebp, eip; + asm volatile ("mov %%esp, %0" : "=r" (esp)); + asm volatile ("mov %%ebp, %0" : "=r" (ebp)); + eip = read_eip(); + if (eip == 0x10000) { + /* Returned from EIP after task switch, we have + * finished switching. */ + fix_signal_stacks(); + + /* XXX: Signals */ + if (!current_process->finished) { + if (current_process->signal_queue->length > 0) { + node_t * node = list_dequeue(current_process->signal_queue); + signal_t * sig = node->value; + free(node); + handle_signal((process_t *)current_process, sig); + } + } + + return; + } + + /* Remember this process' ESP/EBP/EIP */ + current_process->thread.eip = eip; + current_process->thread.esp = esp; + current_process->thread.ebp = ebp; + current_process->running = 0; + + /* Save floating point state */ + switch_fpu(); + + if (reschedule && current_process != kernel_idle_task) { + /* And reinsert it into the ready queue */ + make_process_ready((process_t *)current_process); + } + + /* Switch to the next task */ + switch_next(); +} + +/* + * Immediately switch to the next task. + * + * Does not store the ESP/EBP/EIP of the current thread. + */ +void switch_next(void) { + uintptr_t esp, ebp, eip; + /* Get the next available process */ + current_process = next_ready_process(); + /* Retreive the ESP/EBP/EIP */ + eip = current_process->thread.eip; + esp = current_process->thread.esp; + ebp = current_process->thread.ebp; + unswitch_fpu(); + + /* Validate */ + if ((eip < (uintptr_t)&code) || (eip > (uintptr_t)heap_end)) { + debug_print(WARNING, "Skipping broken process %d! [eip=0x%x <0x%x or >0x%x]", current_process->id, eip, &code, &end); + switch_next(); + } + + if (current_process->finished) { + debug_print(WARNING, "Tried to switch to process %d, but it claims it is finished.", current_process->id); + switch_next(); + } + + /* Set the page directory */ + current_directory = current_process->thread.page_directory; + switch_page_directory(current_directory); + /* Set the kernel stack in the TSS */ + set_kernel_stack(current_process->image.stack); + + if (current_process->started) { + if (!current_process->signal_kstack) { + if (current_process->signal_queue->length > 0) { + current_process->signal_kstack = malloc(KERNEL_STACK_SIZE); + current_process->signal_state.esp = current_process->thread.esp; + current_process->signal_state.eip = current_process->thread.eip; + current_process->signal_state.ebp = current_process->thread.ebp; + memcpy(current_process->signal_kstack, (void *)(current_process->image.stack - KERNEL_STACK_SIZE), KERNEL_STACK_SIZE); + } + } + } else { + current_process->started = 1; + } + + current_process->running = 1; + + /* Jump, baby, jump */ + asm volatile ( + "mov %0, %%ebx\n" + "mov %1, %%esp\n" + "mov %2, %%ebp\n" + "mov %3, %%cr3\n" + "mov $0x10000, %%eax\n" /* read_eip() will return 0x10000 */ + "jmp *%%ebx" + : : "r" (eip), "r" (esp), "r" (ebp), "r" (current_directory->physical_address) + : "%ebx", "%esp", "%eax"); +} + +extern void enter_userspace(uintptr_t location, uintptr_t stack); + +/* + * Enter ring 3 and jump to `location`. + * + * @param location Address to jump to in user space + * @param argc Argument count + * @param argv Argument pointers + * @param stack Userspace stack address + */ +void +enter_user_jmp(uintptr_t location, int argc, char ** argv, uintptr_t stack) { + IRQ_OFF; + set_kernel_stack(current_process->image.stack); + + PUSH(stack, uintptr_t, (uintptr_t)argv); + PUSH(stack, int, argc); + enter_userspace(location, stack); +} + +/* + * Dequeue the current task and set it as finished + * + * @param retval Set the return value to this. + */ +void task_exit(int retval) { + /* Free the image memory */ + if (__builtin_expect(current_process->id == 0,0)) { + /* This is probably bad... */ + switch_next(); + return; + } + cleanup_process((process_t *)current_process, retval); + + process_t * parent = process_get_parent((process_t *)current_process); + + if (parent && !parent->finished) { + wakeup_queue(parent->wait_queue); + } + + switch_next(); +} + +/* + * Call task_exit() and immediately STOP if we can't. + */ +void kexit(int retval) { + task_exit(retval); + debug_print(CRITICAL, "Process returned from task_exit! Environment is definitely unclean. Stopping."); + STOP; +} diff --git a/kernel/sys/version.c b/kernel/sys/version.c new file mode 100644 index 00000000..c13dd5f3 --- /dev/null +++ b/kernel/sys/version.c @@ -0,0 +1,56 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2017 Kevin Lange + */ + +#include + +/* Kernel name. If you change this, you're not + * my friend any more. */ +char * __kernel_name = "toaru"; + +/* This really shouldn't change, and if it does, + * always ensure it still has the correct arguments + * when used as a vsprintf() format. */ +char * __kernel_version_format = "%d.%d.%d-%s"; + +/* Version numbers X.Y.Z */ +int __kernel_version_major = 1; +int __kernel_version_minor = 2; +int __kernel_version_lower = 2; + +/* Kernel build suffix, which doesn't necessarily + * mean anything, but can be used to distinguish + * between different features included while + * building multiple kernels. */ +#ifdef KERNEL_GIT_TAG +# define STR(x) #x +# define STRSTR(x) STR(x) +# define KERNEL_VERSION_SUFFIX STRSTR(KERNEL_GIT_TAG) +#else +# define KERNEL_VERSION_SUFFIX "r" +#endif +char * __kernel_version_suffix = KERNEL_VERSION_SUFFIX; + +/* The release codename. */ +char * __kernel_version_codename = "touma"; + +/* Build architecture (should probably not be + * here as a string, but rather some sort of + * preprocessor macro, or pulled from a script) */ +char * __kernel_arch = "i686"; + +/* Rebuild from clean to reset these. */ +char * __kernel_build_date = __DATE__; +char * __kernel_build_time = __TIME__; + +#if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__) || defined(__INTEL_COMPILER)) +# define COMPILER_VERSION "gcc " __VERSION__ +#elif (defined(__clang__)) +# define COMPILER_VERSION "clang " __clang_version__ +#else +# define COMPILER_VERSION "unknown-compiler how-did-you-do-that" +#endif + +char * __kernel_compiler_version = COMPILER_VERSION; diff --git a/kernel/task.S b/kernel/task.S new file mode 100644 index 00000000..1b64fd01 --- /dev/null +++ b/kernel/task.S @@ -0,0 +1,64 @@ +.section .text +.align 4 + +/* Disable paging mask */ +.set dp, 0x7FFFFFFF +/* Enable paging mask */ +.set ep, 0x80000000 + +.global copy_page_physical +.type copy_page_physical, @function + +copy_page_physical: + /* Preserve contents of EBX */ + push %ebx + + /* Preserve contents of EFLAGS */ + pushf + cli + + /* Load source and destination addresses */ + mov 12(%esp), %ebx + mov 16(%esp), %ecx + + /* Get control register and disable paging*/ + mov %cr0, %edx + and $dp, %edx + mov %edx, %cr0 + + /* Copy 4096 bytes */ + mov $0x400, %edx +.page_loop: + /* Get word at source address */ + mov (%ebx), %eax + + /* Store it at destination address */ + mov %eax, (%ecx) + + /* Increment source and destination addresses to next word */ + add $4, %ebx + add $4, %ecx + + /* One less word to copy */ + dec %edx + jnz .page_loop + + /* Get control register again and enable paging */ + mov %cr0, %edx + or $ep, %edx + mov %edx, %cr0 + + /* Restore EFLAGS */ + popf + + /* Restore EBX */ + pop %ebx + ret + +/* Read EIP */ +.global read_eip +.type read_eip, @function + +read_eip: + mov (%esp), %eax + ret diff --git a/kernel/tss.S b/kernel/tss.S new file mode 100644 index 00000000..0812faaf --- /dev/null +++ b/kernel/tss.S @@ -0,0 +1,10 @@ +.section .text +.align 4 + +.global tss_flush +.type tss_flush, @function + +tss_flush: + mov $0x2B, %ax + ltr %ax + ret diff --git a/kernel/user.S b/kernel/user.S new file mode 100644 index 00000000..df8a27d3 --- /dev/null +++ b/kernel/user.S @@ -0,0 +1,61 @@ +/* Return to Userspace (from thread creation) */ + +.global return_to_userspace +.type return_to_userspace, @function + +return_to_userspace: + pop %gs + pop %fs + pop %es + pop %ds + popa + add $8, %esp + iret + +/* Enter userspace (ring3) */ +.global enter_userspace +.type enter_userspace, @function + +.set MAGIC, 0xDECADE21 + +enter_userspace: + pushl %ebp + mov %esp, %ebp + mov 0xC(%ebp), %edx + mov %edx, %esp + pushl $MAGIC + + /* Segement selector */ + mov $0x23,%ax + + /* Save segement registers */ + mov %eax, %ds + mov %eax, %es + mov %eax, %fs + mov %eax, %gs + /* %ss is handled by iret */ + + /* Store stack address in %eax */ + mov %esp, %eax + + /* Data segmenet with bottom 2 bits set for ring3 */ + pushl $0x23 + + /* Push the stack address */ + pushl %eax + + /* Push flags and fix interrupt flag */ + pushf + popl %eax + + /* Request ring3 */ + orl $0x200, %eax + pushl %eax + pushl $0x1B + + /* Push entry point */ + pushl 0x8(%ebp) + + iret + popl %ebp + ret diff --git a/modules/ac97.c b/modules/ac97.c new file mode 100644 index 00000000..a5cf1256 --- /dev/null +++ b/modules/ac97.c @@ -0,0 +1,302 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015 Michael Gerow + * Copyright (C) 2015 Kevin Lange + * + * Driver for the Intel AC'97. + * + * See . + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Utility macros */ +#define N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) + +/* BARs! */ +#define AC97_NAMBAR 0x10 /* Native Audio Mixer Base Address Register */ +#define AC97_NABMBAR 0x14 /* Native Audio Bus Mastering Base Address Register */ + +/* Bus mastering IO port offsets */ +#define AC97_PO_BDBAR 0x10 /* PCM out buffer descriptor BAR */ +#define AC97_PO_CIV 0x14 /* PCM out current index value */ +#define AC97_PO_LVI 0x15 /* PCM out last valid index */ +#define AC97_PO_SR 0x16 /* PCM out status register */ +#define AC97_PO_PICB 0x18 /* PCM out position in current buffer register */ +#define AC97_PO_CR 0x1B /* PCM out control register */ + +/* Bus mastering misc */ +/* Buffer descriptor list constants */ +#define AC97_BDL_LEN 32 /* Buffer descriptor list length */ +#define AC97_BDL_BUFFER_LEN 0x1000 /* Length of buffer in BDL */ +#define AC97_CL_GET_LENGTH(cl) ((cl) & 0xFFFF) /* Decode length from cl */ +#define AC97_CL_SET_LENGTH(cl, v) ((cl) = (v) & 0xFFFF) /* Encode length to cl */ +#define AC97_CL_BUP ((uint32_t)1 << 30) /* Buffer underrun policy in cl */ +#define AC97_CL_IOC ((uint32_t)1 << 31) /* Interrupt on completion flag in cl */ + +/* PCM out control register flags */ +#define AC97_X_CR_RPBM (1 << 0) /* Run/pause bus master */ +#define AC97_X_CR_RR (1 << 1) /* Reset registers */ +#define AC97_X_CR_LVBIE (1 << 2) /* Last valid buffer interrupt enable */ +#define AC97_X_CR_FEIE (1 << 3) /* FIFO error interrupt enable */ +#define AC97_X_CR_IOCE (1 << 4) /* Interrupt on completion enable */ + +/* Status register flags */ +#define AC97_X_SR_DCH (1 << 0) /* DMA controller halted */ +#define AC97_X_SR_CELV (1 << 1) /* Current equals last valid */ +#define AC97_X_SR_LVBCI (1 << 2) /* Last valid buffer completion interrupt */ +#define AC97_X_SR_BCIS (1 << 3) /* Buffer completion interrupt status */ +#define AC97_X_SR_FIFOE (1 << 3) /* FIFO error */ + +/* Mixer IO port offsets */ +#define AC97_RESET 0x00 +#define AC97_MASTER_VOLUME 0x02 +#define AC97_AUX_OUT_VOLUME 0x04 +#define AC97_MONO_VOLUME 0x06 +#define AC97_PCM_OUT_VOLUME 0x18 + +/* snd values */ +#define AC97_SND_NAME "Intel AC'97" +#define AC97_PLAYBACK_SPEED 48000 +#define AC97_PLAYBACK_FORMAT SND_FORMAT_L16SLE + +/* An entry in a buffer dscriptor list */ +typedef struct { + uint32_t pointer; /* Pointer to buffer */ + uint32_t cl; /* Control values and buffer length */ +} __attribute__((packed)) ac97_bdl_entry_t; + +typedef struct { + uint32_t pci_device; + uint16_t nabmbar; /* Native audio bus mastring BAR */ + uint16_t nambar; /* Native audio mixing BAR */ + size_t irq; /* This ac97's irq */ + uint8_t lvi; /* The currently set last valid index */ + uint8_t bits; /* How many bits of volume are supported (5 or 6) */ + ac97_bdl_entry_t * bdl; /* Buffer descriptor list */ + uint16_t * bufs[AC97_BDL_LEN]; /* Virtual addresses for buffers in BDL */ + uint32_t bdl_p; + uint32_t mask; +} ac97_device_t; + +static ac97_device_t _device; + +#define AC97_KNOB_PCM_OUT (SND_KNOB_VENDOR + 0) + +static snd_knob_t _knobs[] = { + { + "Master", + SND_KNOB_MASTER + }, + { + "PCM Out", + SND_KNOB_VENDOR + 0 + } +}; + +static int ac97_mixer_read(uint32_t knob_id, uint32_t *val); +static int ac97_mixer_write(uint32_t knob_id, uint32_t val); + +static snd_device_t _snd = { + .name = AC97_SND_NAME, + .device = &_device, + .playback_speed = AC97_PLAYBACK_SPEED, + .playback_format = AC97_PLAYBACK_FORMAT, + + .knobs = _knobs, + .num_knobs = N_ELEMENTS(_knobs), + + .mixer_read = ac97_mixer_read, + .mixer_write = ac97_mixer_write, +}; + +/* + * This could be unnecessary if we instead allocate just two buffers and make + * the ac97 think there are more. + */ + +static void find_ac97(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + + ac97_device_t * ac97 = extra; + + if ((vendorid == 0x8086) && (deviceid == 0x2415)) { + ac97->pci_device = device; + } + +} + +#define DIVISION 0x1000 +static int irq_handler(struct regs * regs) { + uint16_t sr = inports(_device.nabmbar + AC97_PO_SR); + if (sr & AC97_X_SR_LVBCI) { + outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_LVBCI); + } else if (sr & AC97_X_SR_BCIS) { + size_t f = (_device.lvi + 2) % AC97_BDL_LEN; + for (size_t i = 0; i < AC97_BDL_BUFFER_LEN * sizeof(*_device.bufs[0]); i += DIVISION) { + snd_request_buf(&_snd, DIVISION, (uint8_t *)_device.bufs[f] + i); + switch_task(1); + } + _device.lvi = (_device.lvi + 1) % AC97_BDL_LEN; + outportb(_device.nabmbar + AC97_PO_LVI, _device.lvi); + outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_BCIS); + } else if (sr & AC97_X_SR_FIFOE) { + outports(_device.nabmbar + AC97_PO_SR, AC97_X_SR_FIFOE); + } else { + return 0; + } + + irq_ack(_device.irq); + return 1; +} + +/* Currently we just assume right and left are the same */ +static int ac97_mixer_read(uint32_t knob_id, uint32_t *val) { + uint16_t tmp; + switch (knob_id) { + case SND_KNOB_MASTER: + tmp = inports(_device.nambar + AC97_MASTER_VOLUME); + if (tmp == 0x8000) { + *val = 0; + } else { + /* 6 bit value */ + *val = (tmp & _device.mask) << (sizeof(*val) * 8 - _device.bits); + *val = ~*val; + *val &= (uint32_t)_device.mask << (sizeof(*val) * 8 - _device.bits); + } + break; + case AC97_KNOB_PCM_OUT: + tmp = inports(_device.nambar + AC97_PCM_OUT_VOLUME); + if (tmp == 0x8000) { + *val = 0; + } else { + /* 5 bit value */ + *val = (tmp & 0x1f) << (sizeof(*val) * 8 - 5); + *val = ~*val; + *val &= 0x1f << (sizeof(*val) * 8 - 5); + } + break; + + default: + return -1; + } + + return 0; +} + +static int ac97_mixer_write(uint32_t knob_id, uint32_t val) { + switch (knob_id) { + case SND_KNOB_MASTER: { + uint16_t encoded; + if (val == 0x0) { + encoded = 0x8000; + } else { + /* 0 is the highest volume */ + val = ~val; + /* 6 bit value */ + val >>= (sizeof(val) * 8 - _device.bits); + encoded = (val & 0xFF) | (val << 8); + } + outports(_device.nambar + AC97_MASTER_VOLUME, encoded); + break; + } + + case AC97_KNOB_PCM_OUT: { + uint16_t encoded; + if (val == 0x0) { + encoded = 0x8000; + } else { + /* 0 is the highest volume */ + val = ~val; + /* 5 bit value */ + val >>= (sizeof(val) * 8 - 5); + encoded = (val & 0xFF) | (val << 8); + } + outports(_device.nambar + AC97_PCM_OUT_VOLUME, encoded); + break; + } + + default: + return -1; + } + + return 0; +} + +static int init(void) { + debug_print(NOTICE, "Initializing AC97"); + pci_scan(&find_ac97, -1, &_device); + if (!_device.pci_device) { + return 1; + } + _device.nabmbar = pci_read_field(_device.pci_device, AC97_NABMBAR, 2) & ((uint32_t) -1) << 1; + _device.nambar = pci_read_field(_device.pci_device, PCI_BAR0, 4) & ((uint32_t) -1) << 1; + _device.irq = pci_read_field(_device.pci_device, PCI_INTERRUPT_LINE, 1); + irq_install_handler(_device.irq, irq_handler); + /* Enable all matter of interrupts */ + outportb(_device.nabmbar + AC97_PO_CR, AC97_X_CR_FEIE | AC97_X_CR_IOCE); + + /* Enable bus mastering and disable memory mapped space */ + pci_write_field(_device.pci_device, PCI_COMMAND, 2, 0x5); + /* Default the PCM output to full volume. */ + outports(_device.nambar + AC97_PCM_OUT_VOLUME, 0x0000); + + /* Allocate our BDL and our buffers */ + _device.bdl = (void *)kmalloc_p(AC97_BDL_LEN * sizeof(*_device.bdl), &_device.bdl_p); + memset(_device.bdl, 0, AC97_BDL_LEN * sizeof(*_device.bdl)); + for (int i = 0; i < AC97_BDL_LEN; i++) { + _device.bufs[i] = (uint16_t *)kmalloc_p(AC97_BDL_BUFFER_LEN * sizeof(*_device.bufs[0]), + &_device.bdl[i].pointer); + memset(_device.bufs[i], 0, AC97_BDL_BUFFER_LEN * sizeof(*_device.bufs[0])); + AC97_CL_SET_LENGTH(_device.bdl[i].cl, AC97_BDL_BUFFER_LEN); + /* Set all buffers to interrupt */ + _device.bdl[i].cl |= AC97_CL_IOC; + + } + /* Tell the ac97 where our BDL is */ + outportl(_device.nabmbar + AC97_PO_BDBAR, _device.bdl_p); + /* Set the LVI to be the last index */ + _device.lvi = 2; + outportb(_device.nabmbar + AC97_PO_LVI, _device.lvi); + + /* detect whether device supports MSB */ + outports(_device.nambar + AC97_MASTER_VOLUME, 0x2020); + uint16_t t = inports(_device.nambar + AC97_MASTER_VOLUME) & 0x1f; + if (t == 0x1f) { + debug_print(WARNING, "This device only supports 5 bits of audio volume."); + _device.bits = 5; + _device.mask = 0x1f; + outports(_device.nambar + AC97_MASTER_VOLUME, 0x0f0f); + } else { + _device.bits = 6; + _device.mask = 0x3f; + outports(_device.nambar + AC97_MASTER_VOLUME, 0x1f1f); + } + + snd_register(&_snd); + + /* Start things playing */ + outportb(_device.nabmbar + AC97_PO_CR, inportb(_device.nabmbar + AC97_PO_CR) | AC97_X_CR_RPBM); + debug_print(NOTICE, "AC97 initialized successfully"); + + return 0; +} + +static int fini(void) { + snd_unregister(&_snd); + + free(_device.bdl); + for (int i = 0; i < AC97_BDL_LEN; i++) { + free(_device.bufs[i]); + } + return 0; +} + +MODULE_DEF(ac97, init, fini); +MODULE_DEPENDS(snd); diff --git a/modules/ata.c b/modules/ata.c new file mode 100644 index 00000000..131f43da --- /dev/null +++ b/modules/ata.c @@ -0,0 +1,841 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + * + * ATA Disk Driver + * + * Provides raw block access to an (Parallel) ATA drive. + */ + +#include +#include +#include +#include +#include +#include + +#include + +/* TODO: Move this to mod/ata.h */ +#include + +static char ata_drive_char = 'a'; +static int cdrom_number = 0; +static uint32_t ata_pci = 0x00000000; +static list_t * atapi_waiter; +static int atapi_in_progress = 0; + +typedef union { + uint8_t command_bytes[12]; + uint16_t command_words[6]; +} atapi_command_t; + +/* 8086:7010 */ +static void find_ata_pci(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + if ((vendorid == 0x8086) && (deviceid == 0x7010 || deviceid == 0x7111)) { + *((uint32_t *)extra) = device; + } +} + +typedef struct { + uintptr_t offset; + uint16_t bytes; + uint16_t last; +} prdt_t; + +struct ata_device { + int io_base; + int control; + int slave; + int is_atapi; + ata_identify_t identity; + prdt_t * dma_prdt; + uintptr_t dma_prdt_phys; + uint8_t * dma_start; + uintptr_t dma_start_phys; + uint32_t bar4; + uint32_t atapi_lba; + uint32_t atapi_sector_size; +}; + +static struct ata_device ata_primary_master = {.io_base = 0x1F0, .control = 0x3F6, .slave = 0}; +static struct ata_device ata_primary_slave = {.io_base = 0x1F0, .control = 0x3F6, .slave = 1}; +static struct ata_device ata_secondary_master = {.io_base = 0x170, .control = 0x376, .slave = 0}; +static struct ata_device ata_secondary_slave = {.io_base = 0x170, .control = 0x376, .slave = 1}; + +//static volatile uint8_t ata_lock = 0; +static spin_lock_t ata_lock = { 0 }; + +/* TODO support other sector sizes */ +#define ATA_SECTOR_SIZE 512 + +static void ata_device_read_sector(struct ata_device * dev, uint32_t lba, uint8_t * buf); +static void ata_device_read_sector_atapi(struct ata_device * dev, uint32_t lba, uint8_t * buf); +static void ata_device_write_sector_retry(struct ata_device * dev, uint32_t lba, uint8_t * buf); +static uint32_t read_ata(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static uint32_t write_ata(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static void open_ata(fs_node_t *node, unsigned int flags); +static void close_ata(fs_node_t *node); + +static uint64_t ata_max_offset(struct ata_device * dev) { + uint64_t sectors = dev->identity.sectors_48; + if (!sectors) { + /* Fall back to sectors_28 */ + sectors = dev->identity.sectors_28; + } + + return sectors * ATA_SECTOR_SIZE; +} + +static uint64_t atapi_max_offset(struct ata_device * dev) { + uint64_t max_sector = dev->atapi_lba; + + if (!max_sector) return 0; + + return (max_sector + 1) * dev->atapi_sector_size; +} + +static uint32_t read_ata(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + + struct ata_device * dev = (struct ata_device *)node->device; + + unsigned int start_block = offset / ATA_SECTOR_SIZE; + unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; + + unsigned int x_offset = 0; + + if (offset > ata_max_offset(dev)) { + return 0; + } + + if (offset + size > ata_max_offset(dev)) { + unsigned int i = ata_max_offset(dev) - offset; + size = i; + } + + if (offset % ATA_SECTOR_SIZE) { + unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); + char * tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, start_block, (uint8_t *)tmp); + + memcpy(buffer, (void *)((uintptr_t)tmp + (offset % ATA_SECTOR_SIZE)), prefix_size); + + free(tmp); + + x_offset += prefix_size; + start_block++; + } + + if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) { + unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; + char * tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, end_block, (uint8_t *)tmp); + + memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, postfix_size); + + free(tmp); + + end_block--; + } + + while (start_block <= end_block) { + ata_device_read_sector(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); + x_offset += ATA_SECTOR_SIZE; + start_block++; + } + + return size; +} + +static uint32_t read_atapi(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + + struct ata_device * dev = (struct ata_device *)node->device; + + unsigned int start_block = offset / dev->atapi_sector_size; + unsigned int end_block = (offset + size - 1) / dev->atapi_sector_size; + + unsigned int x_offset = 0; + + if (offset > atapi_max_offset(dev)) { + return 0; + } + + if (offset + size > atapi_max_offset(dev)) { + unsigned int i = atapi_max_offset(dev) - offset; + size = i; + } + + if (offset % dev->atapi_sector_size) { + unsigned int prefix_size = (dev->atapi_sector_size - (offset % dev->atapi_sector_size)); + char * tmp = malloc(dev->atapi_sector_size); + ata_device_read_sector_atapi(dev, start_block, (uint8_t *)tmp); + + memcpy(buffer, (void *)((uintptr_t)tmp + (offset % dev->atapi_sector_size)), prefix_size); + + free(tmp); + + x_offset += prefix_size; + start_block++; + } + + if ((offset + size) % dev->atapi_sector_size && start_block <= end_block) { + unsigned int postfix_size = (offset + size) % dev->atapi_sector_size; + char * tmp = malloc(dev->atapi_sector_size); + ata_device_read_sector_atapi(dev, end_block, (uint8_t *)tmp); + + memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, postfix_size); + + free(tmp); + + end_block--; + } + + while (start_block <= end_block) { + ata_device_read_sector_atapi(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); + x_offset += dev->atapi_sector_size; + start_block++; + } + + return size; +} + + +static uint32_t write_ata(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + struct ata_device * dev = (struct ata_device *)node->device; + + unsigned int start_block = offset / ATA_SECTOR_SIZE; + unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; + + unsigned int x_offset = 0; + + if (offset > ata_max_offset(dev)) { + return 0; + } + + if (offset + size > ata_max_offset(dev)) { + unsigned int i = ata_max_offset(dev) - offset; + size = i; + } + + if (offset % ATA_SECTOR_SIZE) { + unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); + + char * tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, start_block, (uint8_t *)tmp); + + debug_print(NOTICE, "Writing first block"); + + memcpy((void *)((uintptr_t)tmp + (offset % ATA_SECTOR_SIZE)), buffer, prefix_size); + ata_device_write_sector_retry(dev, start_block, (uint8_t *)tmp); + + free(tmp); + x_offset += prefix_size; + start_block++; + } + + if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) { + unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; + + char * tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, end_block, (uint8_t *)tmp); + + debug_print(NOTICE, "Writing last block"); + + memcpy(tmp, (void *)((uintptr_t)buffer + size - postfix_size), postfix_size); + + ata_device_write_sector_retry(dev, end_block, (uint8_t *)tmp); + + free(tmp); + end_block--; + } + + while (start_block <= end_block) { + ata_device_write_sector_retry(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); + x_offset += ATA_SECTOR_SIZE; + start_block++; + } + + return size; +} + +static void open_ata(fs_node_t * node, unsigned int flags) { + return; +} + +static void close_ata(fs_node_t * node) { + return; +} + +static fs_node_t * atapi_device_create(struct ata_device * device) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + sprintf(fnode->name, "cdrom%d", cdrom_number); + fnode->device = device; + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0660; + fnode->length = atapi_max_offset(device); + fnode->flags = FS_BLOCKDEVICE; + fnode->read = read_atapi; + fnode->write = NULL; /* no write support */ + fnode->open = open_ata; + fnode->close = close_ata; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; /* TODO, identify, etc? */ + return fnode; +} + + +static fs_node_t * ata_device_create(struct ata_device * device) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + sprintf(fnode->name, "atadev%d", ata_drive_char - 'a'); + fnode->device = device; + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0660; + fnode->length = ata_max_offset(device); /* TODO */ + fnode->flags = FS_BLOCKDEVICE; + fnode->read = read_ata; + fnode->write = write_ata; + fnode->open = open_ata; + fnode->close = close_ata; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; /* TODO, identify, etc? */ + return fnode; +} + +static void ata_io_wait(struct ata_device * dev) { + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); +} + +static int ata_status_wait(struct ata_device * dev, int timeout) { + int status; + if (timeout > 0) { + int i = 0; + while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY && (i < timeout)) i++; + } else { + while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY); + } + return status; +} + +static int ata_wait(struct ata_device * dev, int advanced) { + uint8_t status = 0; + + ata_io_wait(dev); + + status = ata_status_wait(dev, -1); + + if (advanced) { + status = inportb(dev->io_base + ATA_REG_STATUS); + if (status & ATA_SR_ERR) return 1; + if (status & ATA_SR_DF) return 1; + if (!(status & ATA_SR_DRQ)) return 1; + } + + return 0; +} + +static void ata_soft_reset(struct ata_device * dev) { + outportb(dev->control, 0x04); + ata_io_wait(dev); + outportb(dev->control, 0x00); +} + +static int ata_irq_handler(struct regs *r) { + inportb(ata_primary_master.io_base + ATA_REG_STATUS); + if (atapi_in_progress) { + wakeup_queue(atapi_waiter); + } + irq_ack(14); + return 1; +} + +static int ata_irq_handler_s(struct regs *r) { + inportb(ata_secondary_master.io_base + ATA_REG_STATUS); + if (atapi_in_progress) { + wakeup_queue(atapi_waiter); + } + irq_ack(15); + return 1; +} + +static void ata_device_init(struct ata_device * dev) { + + debug_print(NOTICE, "Initializing IDE device on bus %d", dev->io_base); + + outportb(dev->io_base + 1, 1); + outportb(dev->control, 0); + + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + + outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + ata_io_wait(dev); + + int status = inportb(dev->io_base + ATA_REG_COMMAND); + debug_print(INFO, "Device status: %d", status); + + ata_wait(dev, 0); + + uint16_t * buf = (uint16_t *)&dev->identity; + + for (int i = 0; i < 256; ++i) { + buf[i] = inports(dev->io_base); + } + + uint8_t * ptr = (uint8_t *)&dev->identity.model; + for (int i = 0; i < 39; i+=2) { + uint8_t tmp = ptr[i+1]; + ptr[i+1] = ptr[i]; + ptr[i] = tmp; + } + + dev->is_atapi = 0; + + debug_print(NOTICE, "Device Name: %s", dev->identity.model); + debug_print(NOTICE, "Sectors (48): %d", (uint32_t)dev->identity.sectors_48); + debug_print(NOTICE, "Sectors (24): %d", dev->identity.sectors_28); + + debug_print(NOTICE, "Setting up DMA..."); + dev->dma_prdt = (void *)kvmalloc_p(sizeof(prdt_t) * 1, &dev->dma_prdt_phys); + dev->dma_start = (void *)kvmalloc_p(4096, &dev->dma_start_phys); + + debug_print(NOTICE, "Putting prdt at 0x%x (0x%x phys)", dev->dma_prdt, dev->dma_prdt_phys); + debug_print(NOTICE, "Putting prdt[0] at 0x%x (0x%x phys)", dev->dma_start, dev->dma_start_phys); + + dev->dma_prdt[0].offset = dev->dma_start_phys; + dev->dma_prdt[0].bytes = 512; + dev->dma_prdt[0].last = 0x8000; + + debug_print(NOTICE, "ATA PCI device ID: 0x%x", ata_pci); + + uint16_t command_reg = pci_read_field(ata_pci, PCI_COMMAND, 4); + debug_print(NOTICE, "COMMAND register before: 0x%4x", command_reg); + if (command_reg & (1 << 2)) { + debug_print(NOTICE, "Bus mastering already enabled."); + } else { + command_reg |= (1 << 2); /* bit 2 */ + debug_print(NOTICE, "Enabling bus mastering..."); + pci_write_field(ata_pci, PCI_COMMAND, 4, command_reg); + command_reg = pci_read_field(ata_pci, PCI_COMMAND, 4); + debug_print(NOTICE, "COMMAND register after: 0x%4x", command_reg); + } + + dev->bar4 = pci_read_field(ata_pci, PCI_BAR4, 4); + debug_print(NOTICE, "BAR4: 0x%x", dev->bar4); + + if (dev->bar4 & 0x00000001) { + dev->bar4 = dev->bar4 & 0xFFFFFFFC; + } else { + debug_print(WARNING, "? ATA bus master registers are /usually/ I/O ports.\n"); + return; /* No DMA because we're not sure what to do here */ + } + +#if 0 + pci_write_field(ata_pci, PCI_INTERRUPT_LINE, 1, 0xFE); + if (pci_read_field(ata_pci, PCI_INTERRUPT_LINE, 1) == 0xFE) { + /* needs assignment */ + pci_write_field(ata_pci, PCI_INTERRUPT_LINE, 1, 14); + } +#endif + +} + +static void atapi_device_init(struct ata_device * dev) { + + dev->is_atapi = 1; + + outportb(dev->io_base + 1, 1); + outportb(dev->control, 0); + + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + + outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET); + ata_io_wait(dev); + + int status = inportb(dev->io_base + ATA_REG_COMMAND); + debug_print(INFO, "Device status: %d", status); + + ata_wait(dev, 0); + + uint16_t * buf = (uint16_t *)&dev->identity; + + for (int i = 0; i < 256; ++i) { + buf[i] = inports(dev->io_base); + } + + uint8_t * ptr = (uint8_t *)&dev->identity.model; + for (int i = 0; i < 39; i+=2) { + uint8_t tmp = ptr[i+1]; + ptr[i+1] = ptr[i]; + ptr[i] = tmp; + } + + debug_print(NOTICE, "Device Name: %s", dev->identity.model); + + /* Detect medium */ + atapi_command_t command; + command.command_bytes[0] = 0x25; + command.command_bytes[1] = 0; + command.command_bytes[2] = 0; + command.command_bytes[3] = 0; + command.command_bytes[4] = 0; + command.command_bytes[5] = 0; + command.command_bytes[6] = 0; + command.command_bytes[7] = 0; + command.command_bytes[8] = 0; /* bit 0 = PMI (0, last sector) */ + command.command_bytes[9] = 0; /* control */ + command.command_bytes[10] = 0; + command.command_bytes[11] = 0; + + uint16_t bus = dev->io_base; + + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_LBA1, 0x08); + outportb(bus + ATA_REG_LBA2, 0x08); + outportb(bus + ATA_REG_COMMAND, ATA_CMD_PACKET); + + /* poll */ + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; + } + + for (int i = 0; i < 6; ++i) { + outports(bus, command.command_words[i]); + } + + /* poll */ + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error_read; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; + if ((status & ATA_SR_DRQ)) break; + } + + uint16_t data[4]; + + for (int i = 0; i < 4; ++i) { + data[i] = inports(bus); + } + +#define htonl(l) ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24)) + uint32_t lba, blocks;; + memcpy(&lba, &data[0], sizeof(uint32_t)); + lba = htonl(lba); + memcpy(&blocks, &data[2], sizeof(uint32_t)); + blocks = htonl(blocks); + + dev->atapi_lba = lba; + dev->atapi_sector_size = blocks; + + debug_print(WARNING, "Finished! LBA = %x; block length = %x", lba, blocks); + return; + +atapi_error_read: + debug_print(ERROR, "ATAPI error; no medium?"); + return; + +atapi_error: + debug_print(ERROR, "ATAPI early error; unsure"); + return; + +} + +static int ata_device_detect(struct ata_device * dev) { + ata_soft_reset(dev); + ata_io_wait(dev); + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + ata_status_wait(dev, 10000); + + unsigned char cl = inportb(dev->io_base + ATA_REG_LBA1); /* CYL_LO */ + unsigned char ch = inportb(dev->io_base + ATA_REG_LBA2); /* CYL_HI */ + + debug_print(NOTICE, "Device detected: 0x%2x 0x%2x", cl, ch); + if (cl == 0xFF && ch == 0xFF) { + /* Nothing here */ + return 0; + } + if ((cl == 0x00 && ch == 0x00) || + (cl == 0x3C && ch == 0xC3)) { + /* Parallel ATA device, or emulated SATA */ + + char devname[64]; + sprintf((char *)&devname, "/dev/hd%c", ata_drive_char); + fs_node_t * node = ata_device_create(dev); + vfs_mount(devname, node); + ata_drive_char++; + + ata_device_init(dev); + + return 1; + } else if ((cl == 0x14 && ch == 0xEB) || + (cl == 0x69 && ch == 0x96)) { + debug_print(WARNING, "Detected ATAPI device at io-base 0x%3x, control 0x%3x, slave %d", dev->io_base, dev->control, dev->slave); + + char devname[64]; + sprintf((char *)&devname, "/dev/cdrom%d", cdrom_number); + + atapi_device_init(dev); + fs_node_t * node = atapi_device_create(dev); + vfs_mount(devname, node); + + cdrom_number++; + + return 2; + } + + /* TODO: ATAPI, SATA, SATAPI */ + return 0; +} + +static void ata_device_read_sector(struct ata_device * dev, uint32_t lba, uint8_t * buf) { + uint16_t bus = dev->io_base; + uint8_t slave = dev->slave; + + if (dev->is_atapi) return; + + spin_lock(ata_lock); + +#if 0 + int errors = 0; +try_again: +#endif + + ata_wait(dev, 0); + + /* Stop */ + outportb(dev->bar4, 0x00); + + /* Set the PRDT */ + outportl(dev->bar4 + 0x04, dev->dma_prdt_phys); + + /* Enable error, irq status */ + outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); + + /* set read */ + outportb(dev->bar4, 0x08); + + IRQ_ON; + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if (!(status & ATA_SR_BSY)) break; + } + + outportb(bus + ATA_REG_CONTROL, 0x00); + outportb(bus + ATA_REG_HDDEVSEL, 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); + ata_io_wait(dev); + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_SECCOUNT0, 1); + outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); + outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); + outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); + //outportb(bus + ATA_REG_COMMAND, ATA_CMD_READ_PIO); +#if 1 + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; + } +#endif + outportb(bus + ATA_REG_COMMAND, ATA_CMD_READ_DMA); + + ata_io_wait(dev); + + outportb(dev->bar4, 0x08 | 0x01); + + while (1) { + int status = inportb(dev->bar4 + 0x02); + int dstatus = inportb(dev->io_base + ATA_REG_STATUS); + if (!(status & 0x04)) { + continue; + } + if (!(dstatus & ATA_SR_BSY)) { + break; + } + } + IRQ_OFF; + +#if 0 + if (ata_wait(dev, 1)) { + debug_print(WARNING, "Error during ATA read of lba block %d", lba); + errors++; + if (errors > 4) { + debug_print(WARNING, "-- Too many errors trying to read this block. Bailing."); + spin_unlock(ata_lock); + return; + } + goto try_again; + } +#endif + + /* Copy from DMA buffer to output buffer. */ + memcpy(buf, dev->dma_start, 512); + + /* Inform device we are done. */ + outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); + +#if 0 + int size = 256; + inportsm(bus,buf,size); + ata_wait(dev, 0); + outportb(bus + ATA_REG_CONTROL, 0x02); +#endif + spin_unlock(ata_lock); +} + +static void ata_device_read_sector_atapi(struct ata_device * dev, uint32_t lba, uint8_t * buf) { + + if (!dev->is_atapi) return; + + uint16_t bus = dev->io_base; + spin_lock(ata_lock); + + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_LBA1, dev->atapi_sector_size & 0xFF); + outportb(bus + ATA_REG_LBA2, dev->atapi_sector_size >> 8); + outportb(bus + ATA_REG_COMMAND, ATA_CMD_PACKET); + + /* poll */ + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; + } + + atapi_in_progress = 1; + + + atapi_command_t command; + command.command_bytes[0] = 0xA8; + command.command_bytes[1] = 0; + command.command_bytes[2] = (lba >> 0x18) & 0xFF; + command.command_bytes[3] = (lba >> 0x10) & 0xFF; + command.command_bytes[4] = (lba >> 0x08) & 0xFF; + command.command_bytes[5] = (lba >> 0x00) & 0xFF; + command.command_bytes[6] = 0; + command.command_bytes[7] = 0; + command.command_bytes[8] = 0; /* bit 0 = PMI (0, last sector) */ + command.command_bytes[9] = 1; /* control */ + command.command_bytes[10] = 0; + command.command_bytes[11] = 0; + + for (int i = 0; i < 6; ++i) { + outports(bus, command.command_words[i]); + } + + /* Wait */ + sleep_on(atapi_waiter); + + atapi_in_progress = 0; + + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; + } + + uint16_t size_to_read = inportb(bus + ATA_REG_LBA2) << 8; + size_to_read = size_to_read | inportb(bus + ATA_REG_LBA1); + + + inportsm(bus,buf,size_to_read/2); + + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if ((status & ATA_SR_ERR)) goto atapi_error_on_read_setup; + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; + } + +atapi_error_on_read_setup: + spin_unlock(ata_lock); + +} + +static void ata_device_write_sector(struct ata_device * dev, uint32_t lba, uint8_t * buf) { + uint16_t bus = dev->io_base; + uint8_t slave = dev->slave; + + spin_lock(ata_lock); + + outportb(bus + ATA_REG_CONTROL, 0x02); + + ata_wait(dev, 0); + outportb(bus + ATA_REG_HDDEVSEL, 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); + ata_wait(dev, 0); + + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_SECCOUNT0, 0x01); + outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); + outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); + outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); + outportb(bus + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); + ata_wait(dev, 0); + int size = ATA_SECTOR_SIZE / 2; + outportsm(bus,buf,size); + outportb(bus + 0x07, ATA_CMD_CACHE_FLUSH); + ata_wait(dev, 0); + spin_unlock(ata_lock); +} + +static int buffer_compare(uint32_t * ptr1, uint32_t * ptr2, size_t size) { + assert(!(size % 4)); + size_t i = 0; + while (i < size) { + if (*ptr1 != *ptr2) return 1; + ptr1++; + ptr2++; + i += sizeof(uint32_t); + } + return 0; +} + +static void ata_device_write_sector_retry(struct ata_device * dev, uint32_t lba, uint8_t * buf) { + uint8_t * read_buf = malloc(ATA_SECTOR_SIZE); + do { + ata_device_write_sector(dev, lba, buf); + ata_device_read_sector(dev, lba, read_buf); + } while (buffer_compare((uint32_t *)buf, (uint32_t *)read_buf, ATA_SECTOR_SIZE)); + free(read_buf); +} + +static int ata_initialize(void) { + /* Detect drives and mount them */ + + /* Locate ATA device via PCI */ + pci_scan(&find_ata_pci, -1, &ata_pci); + + irq_install_handler(14, ata_irq_handler); + irq_install_handler(15, ata_irq_handler_s); + + atapi_waiter = list_create(); + + ata_device_detect(&ata_primary_master); + ata_device_detect(&ata_primary_slave); + ata_device_detect(&ata_secondary_master); + ata_device_detect(&ata_secondary_slave); + + return 0; +} + +static int ata_finalize(void) { + + return 0; +} + +MODULE_DEF(ata, ata_initialize, ata_finalize); diff --git a/modules/ataold.c b/modules/ataold.c new file mode 100644 index 00000000..05206f95 --- /dev/null +++ b/modules/ataold.c @@ -0,0 +1,412 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + * + * ATA Disk Driver + * + * Provides raw block access to an (Parallel) ATA drive. + */ + +#include +#include +#include +#include +#include + +/* TODO: Move this to mod/ata.h */ +#include + +static char ata_drive_char = 'a'; + +struct ata_device { + int io_base; + int control; + int slave; + ata_identify_t identity; +}; + +//static volatile uint8_t ata_lock = 0; +static spin_lock_t ata_lock = { 0 }; + +/* TODO support other sector sizes */ +#define ATA_SECTOR_SIZE 512 + +static void ata_device_read_sector(struct ata_device * dev, uint32_t lba, uint8_t * buf); +static void ata_device_write_sector_retry(struct ata_device * dev, uint32_t lba, uint8_t * buf); +static uint32_t read_ata(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static uint32_t write_ata(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static void open_ata(fs_node_t *node, unsigned int flags); +static void close_ata(fs_node_t *node); + +static uint64_t ata_max_offset(struct ata_device * dev) { + uint64_t sectors = dev->identity.sectors_48; + if (!sectors) { + /* Fall back to sectors_28 */ + sectors = dev->identity.sectors_28; + } + + return sectors * ATA_SECTOR_SIZE; +} + +static uint32_t read_ata(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + + struct ata_device * dev = (struct ata_device *)node->device; + + unsigned int start_block = offset / ATA_SECTOR_SIZE; + unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; + + unsigned int x_offset = 0; + + if (offset > ata_max_offset(dev)) { + return 0; + } + + if (offset + size > ata_max_offset(dev)) { + unsigned int i = ata_max_offset(dev) - offset; + size = i; + } + + if (offset % ATA_SECTOR_SIZE) { + unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); + char * tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, start_block, (uint8_t *)tmp); + + memcpy(buffer, (void *)((uintptr_t)tmp + (offset % ATA_SECTOR_SIZE)), prefix_size); + + free(tmp); + + x_offset += prefix_size; + start_block++; + } + + if ((offset + size) % ATA_SECTOR_SIZE && start_block < end_block) { + unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; + char * tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, end_block, (uint8_t *)tmp); + + memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, postfix_size); + + free(tmp); + + end_block--; + } + + while (start_block <= end_block) { + ata_device_read_sector(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); + x_offset += ATA_SECTOR_SIZE; + start_block++; + } + + return size; +} + +static uint32_t write_ata(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + struct ata_device * dev = (struct ata_device *)node->device; + + unsigned int start_block = offset / ATA_SECTOR_SIZE; + unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE; + + unsigned int x_offset = 0; + + if (offset > ata_max_offset(dev)) { + return 0; + } + + if (offset + size > ata_max_offset(dev)) { + unsigned int i = ata_max_offset(dev) - offset; + size = i; + } + + if (offset % ATA_SECTOR_SIZE) { + unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE)); + + char * tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, start_block, (uint8_t *)tmp); + + debug_print(NOTICE, "Writing first block"); + + memcpy((void *)((uintptr_t)tmp + (offset % ATA_SECTOR_SIZE)), buffer, prefix_size); + ata_device_write_sector_retry(dev, start_block, (uint8_t *)tmp); + + free(tmp); + x_offset += prefix_size; + start_block++; + } + + if ((offset + size) % ATA_SECTOR_SIZE && start_block < end_block) { + unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE; + + char * tmp = malloc(ATA_SECTOR_SIZE); + ata_device_read_sector(dev, end_block, (uint8_t *)tmp); + + debug_print(NOTICE, "Writing last block"); + + memcpy(tmp, (void *)((uintptr_t)buffer + size - postfix_size), postfix_size); + + ata_device_write_sector_retry(dev, end_block, (uint8_t *)tmp); + + free(tmp); + end_block--; + } + + while (start_block <= end_block) { + ata_device_write_sector_retry(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset)); + x_offset += ATA_SECTOR_SIZE; + start_block++; + } + + return size; +} + +static void open_ata(fs_node_t * node, unsigned int flags) { + return; +} + +static void close_ata(fs_node_t * node) { + return; +} + +static fs_node_t * ata_device_create(struct ata_device * device) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + sprintf(fnode->name, "atadev%d", ata_drive_char - 'a'); + fnode->device = device; + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0660; + fnode->length = ata_max_offset(device); /* TODO */ + fnode->flags = FS_BLOCKDEVICE; + fnode->read = read_ata; + fnode->write = write_ata; + fnode->open = open_ata; + fnode->close = close_ata; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; /* TODO, identify, etc? */ + return fnode; +} + +static void ata_io_wait(struct ata_device * dev) { + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); + inportb(dev->io_base + ATA_REG_ALTSTATUS); +} + +static int ata_status_wait(struct ata_device * dev, int timeout) { + int status; + if (timeout > 0) { + int i = 0; + while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY && (i < timeout)) i++; + } else { + while ((status = inportb(dev->io_base + ATA_REG_STATUS)) & ATA_SR_BSY); + } + return status; +} + +static int ata_wait(struct ata_device * dev, int advanced) { + uint8_t status = 0; + + ata_io_wait(dev); + + status = ata_status_wait(dev, -1); + + if (advanced) { + status = inportb(dev->io_base + ATA_REG_STATUS); + if (status & ATA_SR_ERR) return 1; + if (status & ATA_SR_DF) return 1; + if (!(status & ATA_SR_DRQ)) return 1; + } + + return 0; +} + +static void ata_soft_reset(struct ata_device * dev) { + outportb(dev->control, 0x04); + ata_io_wait(dev); + outportb(dev->control, 0x00); +} + +static void ata_device_init(struct ata_device * dev) { + + debug_print(NOTICE, "Initializing IDE device on bus %d", dev->io_base); + + outportb(dev->io_base + 1, 1); + outportb(dev->control, 0); + + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + + outportb(dev->io_base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + ata_io_wait(dev); + + int status = inportb(dev->io_base + ATA_REG_COMMAND); + debug_print(INFO, "Device status: %d", status); + + ata_wait(dev, 0); + + uint16_t * buf = (uint16_t *)&dev->identity; + + for (int i = 0; i < 256; ++i) { + buf[i] = inports(dev->io_base); + } + + uint8_t * ptr = (uint8_t *)&dev->identity.model; + for (int i = 0; i < 39; i+=2) { + uint8_t tmp = ptr[i+1]; + ptr[i+1] = ptr[i]; + ptr[i] = tmp; + } + + debug_print(NOTICE, "Device Name: %s", dev->identity.model); + debug_print(NOTICE, "Sectors (48): %d", (uint32_t)dev->identity.sectors_48); + debug_print(NOTICE, "Sectors (24): %d", dev->identity.sectors_28); + + outportb(dev->io_base + ATA_REG_CONTROL, 0x02); +} + +static int ata_device_detect(struct ata_device * dev) { + ata_soft_reset(dev); + ata_io_wait(dev); + outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); + ata_io_wait(dev); + ata_status_wait(dev, 10000); + + unsigned char cl = inportb(dev->io_base + ATA_REG_LBA1); /* CYL_LO */ + unsigned char ch = inportb(dev->io_base + ATA_REG_LBA2); /* CYL_HI */ + + debug_print(NOTICE, "Device detected: 0x%2x 0x%2x", cl, ch); + if (cl == 0xFF && ch == 0xFF) { + /* Nothing here */ + return 0; + } + if ((cl == 0x00 && ch == 0x00) || + (cl == 0x3C && ch == 0xC3)) { + /* Parallel ATA device, or emulated SATA */ + + char devname[64]; + sprintf((char *)&devname, "/dev/hd%c", ata_drive_char); + fs_node_t * node = ata_device_create(dev); + vfs_mount(devname, node); + ata_drive_char++; + + ata_device_init(dev); + + return 1; + } + + /* TODO: ATAPI, SATA, SATAPI */ + return 0; +} + +static void ata_device_read_sector(struct ata_device * dev, uint32_t lba, uint8_t * buf) { + uint16_t bus = dev->io_base; + uint8_t slave = dev->slave; + + spin_lock(ata_lock); + + int errors = 0; +try_again: + outportb(bus + ATA_REG_CONTROL, 0x02); + + ata_wait(dev, 0); + + outportb(bus + ATA_REG_HDDEVSEL, 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_SECCOUNT0, 1); + outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); + outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); + outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); + outportb(bus + ATA_REG_COMMAND, ATA_CMD_READ_PIO); + + if (ata_wait(dev, 1)) { + debug_print(WARNING, "Error during ATA read of lba block %d", lba); + errors++; + if (errors > 4) { + debug_print(WARNING, "-- Too many errors trying to read this block. Bailing."); + spin_unlock(ata_lock); + return; + } + goto try_again; + } + + int size = 256; + inportsm(bus,buf,size); + ata_wait(dev, 0); + spin_unlock(ata_lock); +} + +static void ata_device_write_sector(struct ata_device * dev, uint32_t lba, uint8_t * buf) { + uint16_t bus = dev->io_base; + uint8_t slave = dev->slave; + + spin_lock(ata_lock); + + outportb(bus + ATA_REG_CONTROL, 0x02); + + ata_wait(dev, 0); + outportb(bus + ATA_REG_HDDEVSEL, 0xe0 | slave << 4 | (lba & 0x0f000000) >> 24); + ata_wait(dev, 0); + + outportb(bus + ATA_REG_FEATURES, 0x00); + outportb(bus + ATA_REG_SECCOUNT0, 0x01); + outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0); + outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); + outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); + outportb(bus + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); + ata_wait(dev, 0); + int size = ATA_SECTOR_SIZE / 2; + outportsm(bus,buf,size); + outportb(bus + 0x07, ATA_CMD_CACHE_FLUSH); + ata_wait(dev, 0); + spin_unlock(ata_lock); +} + +static int buffer_compare(uint32_t * ptr1, uint32_t * ptr2, size_t size) { + assert(!(size % 4)); + size_t i = 0; + while (i < size) { + if (*ptr1 != *ptr2) return 1; + ptr1++; + ptr2++; + i += sizeof(uint32_t); + } + return 0; +} + +static void ata_device_write_sector_retry(struct ata_device * dev, uint32_t lba, uint8_t * buf) { + uint8_t * read_buf = malloc(ATA_SECTOR_SIZE); + IRQ_OFF; + do { + ata_device_write_sector(dev, lba, buf); + ata_device_read_sector(dev, lba, read_buf); + } while (buffer_compare((uint32_t *)buf, (uint32_t *)read_buf, ATA_SECTOR_SIZE)); + IRQ_RES; + free(read_buf); +} + +static struct ata_device ata_primary_master = {.io_base = 0x1F0, .control = 0x3F6, .slave = 0}; +static struct ata_device ata_primary_slave = {.io_base = 0x1F0, .control = 0x3F6, .slave = 1}; +static struct ata_device ata_secondary_master = {.io_base = 0x170, .control = 0x376, .slave = 0}; +static struct ata_device ata_secondary_slave = {.io_base = 0x170, .control = 0x376, .slave = 1}; + + +static int ata_initialize(void) { + /* Detect drives and mount them */ + + ata_device_detect(&ata_primary_master); + ata_device_detect(&ata_primary_slave); + ata_device_detect(&ata_secondary_master); + ata_device_detect(&ata_secondary_slave); + + return 0; +} + +static int ata_finalize(void) { + + return 0; +} + +MODULE_DEF(ata_legacy, ata_initialize, ata_finalize); diff --git a/modules/crash.c b/modules/crash.c new file mode 100644 index 00000000..81bae5ed --- /dev/null +++ b/modules/crash.c @@ -0,0 +1,33 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include + +DEFINE_SHELL_FUNCTION(crash, "Dereference NULL.") { + fprintf(tty, "*0x0 = %x\n", *((int *)0x00)); + *((int *)0x0) = 0x42; + fprintf(tty, "*0x0 = %x\n", *((int *)0x00)); + return 0; +} + +DEFINE_SHELL_FUNCTION(assert_false, "assert(0)") { + assert(0); + return 0; +} + +static int crash_init(void) { + BIND_SHELL_FUNCTION(crash); + BIND_SHELL_FUNCTION(assert_false); + return 0; +} + +static int crash_fini(void) { + return 0; +} + +MODULE_DEF(crash, crash_init, crash_fini); +MODULE_DEPENDS(debugshell); diff --git a/modules/debug_shell.c b/modules/debug_shell.c new file mode 100644 index 00000000..5d8bac25 --- /dev/null +++ b/modules/debug_shell.c @@ -0,0 +1,820 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + * + * Kernel Debug Shell + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * This is basically the same as a userspace buffered/unbuffered + * termio call. These are the same sorts of things I would use in + * a text editor in userspace, but with the internal kernel calls + * rather than system calls. + */ +static struct termios old; + +void tty_set_unbuffered(fs_node_t * dev) { + ioctl_fs(dev, TCGETS, &old); + struct termios new = old; + new.c_lflag &= (~ICANON & ~ECHO); + ioctl_fs(dev, TCSETSF, &new); +} + +void tty_set_buffered(fs_node_t * dev) { + ioctl_fs(dev, TCSETSF, &old); +} + +void tty_set_vintr(fs_node_t * dev, char vintr) { + struct termios tmp; + ioctl_fs(dev, TCGETS, &tmp); + tmp.c_cc[VINTR] = vintr; + ioctl_fs(dev, TCSETSF, &tmp); +} + +/* + * Quick readline implementation. + * + * Most of these TODOs are things I've done already in older code: + * TODO tabcompletion would be nice + * TODO history is also nice + */ +int debug_shell_readline(fs_node_t * dev, char * linebuf, int max) { + int read = 0; + tty_set_unbuffered(dev); + while (read < max) { + uint8_t buf[1]; + int r = read_fs(dev, 0, 1, (unsigned char *)buf); + if (!r) { + debug_print(WARNING, "Read nothing?"); + continue; + } + linebuf[read] = buf[0]; + if (buf[0] == '\n') { + fprintf(dev, "\n"); + linebuf[read] = 0; + break; + } else if (buf[0] == 0x08) { + if (read > 0) { + fprintf(dev, "\010 \010"); + read--; + linebuf[read] = 0; + } + } else if (buf[0] < ' ') { + switch (buf[0]) { + case 0x04: + if (read == 0) { + fprintf(dev, "exit\n"); + sprintf(linebuf, "exit"); + return strlen(linebuf); + } + break; + case 0x0C: /* ^L */ + /* Should reset display here */ + break; + default: + /* do nothing */ + break; + } + } else { + fprintf(dev, "%c", buf[0]); + read += r; + } + } + tty_set_buffered(dev); + return read; +} + +/* + * Tasklet for running a userspace application. + */ +static void debug_shell_run_sh(void * data, char * name) { + + char * argv[] = { + data, + NULL + }; + int argc = 0; + while (argv[argc]) { + argc++; + } + system(argv[0], argc, argv); /* Run shell */ + + task_exit(42); +} + +static hashmap_t * shell_commands_map = NULL; + +/* + * Shell commands + */ +static int shell_create_userspace_shell(fs_node_t * tty, int argc, char * argv[]) { + int pid = create_kernel_tasklet(debug_shell_run_sh, "[[k-sh]]", "/bin/sh"); + fprintf(tty, "Shell started with pid = %d\n", pid); + int status; + waitpid(pid,&status,0); + return status; +} + +static int shell_replace_login(fs_node_t * tty, int argc, char * argv[]) { + /* We need to fork to get a clean task space */ + create_kernel_tasklet(debug_shell_run_sh, "[[k-sh]]", "/bin/login"); + /* Then exit the shell process */ + task_exit(0); + /* unreachable */ + return 0; +} + +static int shell_echo(fs_node_t * tty, int argc, char * argv[]) { + for (int i = 1; i < argc; ++i) { + fprintf(tty, "%s ", argv[i]); + } + fprintf(tty, "\n"); + return 0; +} + +static int dumb_strcmp(void * a, void *b) { + return strcmp(a, b); +} + +static void dumb_sort(void ** list, size_t length, int (*compare)(void*,void*)) { + for (unsigned int i = 0; i < length-1; ++i) { + for (unsigned int j = 0; j < length-1; ++j) { + if (compare(list[j], list[j+1]) > 0) { + void * t = list[j+1]; + list[j+1] = list[j]; + list[j] = t; + } + } + } +} + +static void print_spaces(fs_node_t * tty, int num_spaces) { + for (int i = 0; i < num_spaces; ++i) { + fprintf(tty, " "); + } +} + +static int shell_help(fs_node_t * tty, int argc, char * argv[]) { + list_t * hash_keys = hashmap_keys(shell_commands_map); + + char ** keys = malloc(sizeof(char *) * hash_keys->length); + + unsigned int i = 0; + unsigned int max_width = 0; + + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + keys[i] = key; + i++; + if (strlen(key) > max_width) { + max_width = strlen(key); + } + } + + dumb_sort((void **)keys, hash_keys->length, &dumb_strcmp); + + for (i = 0; i < hash_keys->length; ++i) { + struct shell_command * c = hashmap_get(shell_commands_map, keys[i]); + fprintf(tty, "\033[1;32m%s\033[0m ", c->name); + print_spaces(tty, max_width- strlen(c->name)); + fprintf(tty, "- %s\n", c->description); + } + + free(keys); + list_free(hash_keys); + free(hash_keys); + + return 0; +} + +static int shell_cd(fs_node_t * tty, int argc, char * argv[]) { + if (argc < 2) { + return 1; + } + char * newdir = argv[1]; + char * path = canonicalize_path(current_process->wd_name, newdir); + fs_node_t * chd = kopen(path, 0); + if (chd) { + if ((chd->flags & FS_DIRECTORY) == 0) { + return 1; + } + close_fs(chd); + free(current_process->wd_name); + current_process->wd_name = malloc(strlen(path) + 1); + memcpy(current_process->wd_name, path, strlen(path) + 1); + return 0; + } else { + return 1; + } +} + +static int shell_ls(fs_node_t * tty, int argc, char * argv[]) { + fs_node_t * wd; + if (argc < 2) { + wd = kopen(current_process->wd_name, 0); + } else { + wd = kopen(argv[1], 0); + } + uint32_t index = 0; + struct dirent * kentry = readdir_fs(wd, index); + while (kentry) { + fprintf(tty, "%s\n", kentry->name); + free(kentry); + + index++; + kentry = readdir_fs(wd, index); + } + close_fs(wd); + return 0; +} + +static int shell_cat(fs_node_t * tty, int argc, char * argv[]) { + if (argc < 2) { + fprintf(tty, "Usage: cat \n"); + return 1; + } + + fs_node_t * node = kopen(argv[1], 0); + if (!node) { + fprintf(tty, "Could not open %s.\n", argv[1]); + return 1; + } + +#define CHUNK_SIZE 4096 + uint8_t * buf = malloc(CHUNK_SIZE); + memset(buf, 0, CHUNK_SIZE); + size_t offset = 0; + while (1) { + size_t r = read_fs(node, offset, CHUNK_SIZE, buf); + if (!r) break; + write_fs(tty, 0, r, buf); + offset += r; + } + + close_fs(node); + return 0; +} + +static int shell_log(fs_node_t * tty, int argc, char * argv[]) { + if (argc < 2) { + fprintf(tty, "Log level is currently %d.\n", debug_level); + fprintf(tty, "Serial logging is %s.\n", !!debug_file ? "enabled" : "disabled"); + fprintf(tty, "Usage: log [on|off] []\n"); + } else { + if (!strcmp(argv[1], "direct")) { + debug_file = kopen("/dev/ttyS0", 0); + if (argc > 2) { + debug_level = atoi(argv[2]); + } + } else if (!strcmp(argv[1], "on")) { + debug_file = tty; + if (argc > 2) { + debug_level = atoi(argv[2]); + } + } else if (!strcmp(argv[1], "off")) { + debug_file = NULL; + } + } + return 0; +} + +static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + + fs_node_t * tty = extra; + + fprintf(tty, "%2x:%2x.%d (%4x, %4x:%4x) %s %s\n", + (int)pci_extract_bus(device), + (int)pci_extract_slot(device), + (int)pci_extract_func(device), + (int)pci_find_type(device), + vendorid, + deviceid, + pci_vendor_lookup(vendorid), + pci_device_lookup(vendorid,deviceid)); + + fprintf(tty, " BAR0: 0x%8x", pci_read_field(device, PCI_BAR0, 4)); + fprintf(tty, " BAR1: 0x%8x", pci_read_field(device, PCI_BAR1, 4)); + fprintf(tty, " BAR2: 0x%8x", pci_read_field(device, PCI_BAR2, 4)); + fprintf(tty, " BAR3: 0x%8x", pci_read_field(device, PCI_BAR3, 4)); + fprintf(tty, " BAR4: 0x%8x", pci_read_field(device, PCI_BAR4, 4)); + fprintf(tty, " BAR6: 0x%8x\n", pci_read_field(device, PCI_BAR5, 4)); + +} + +static int shell_pci(fs_node_t * tty, int argc, char * argv[]) { + pci_scan(&scan_hit_list, -1, tty); + return 0; +} + +static int shell_uid(fs_node_t * tty, int argc, char * argv[]) { + if (argc < 2) { + fprintf(tty, "uid=%d\n", current_process->user); + } else { + current_process->user = atoi(argv[1]); + } + return 0; +} + +char * special_thing = "I am a string from the kernel.\n"; + +static int shell_mod(fs_node_t * tty, int argc, char * argv[]) { + if (argc < 2) { + fprintf(tty, "%s: expected argument\n", argv[0]); + return 1; + } + fs_node_t * file = kopen(argv[1], 0); + if (!file) { + fprintf(tty, "%s: Error loading module '%s': File not found\n", argv[0], argv[1]); + return 1; + } + close_fs(file); + + module_data_t * mod_info = module_load(argv[1]); + if (!mod_info) { + fprintf(tty, "%s: Error loading module '%s'\n", argv[0], argv[1]); + return 1; + } + + fprintf(tty, "Module '%s' loaded at 0x%x\n", mod_info->mod_info->name, mod_info->bin_data); + + return 0; +} + +static int shell_symbols(fs_node_t * tty, int argc, char * argv[]) { + + if (argc > 1 && !strcmp(argv[1],"--all")) { + list_t * hash_keys = hashmap_keys(modules_get_symbols()); + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + uintptr_t a = (uintptr_t)hashmap_get(modules_get_symbols(), key); + fprintf(tty, "0x%x - %s\n", a, key); + } + free(hash_keys); + } else { + + extern char kernel_symbols_start[]; + extern char kernel_symbols_end[]; + + struct ksym { + uintptr_t addr; + char name[]; + } * k = (void*)&kernel_symbols_start; + + while ((uintptr_t)k < (uintptr_t)&kernel_symbols_end) { + fprintf(tty, "0x%x - %s\n", k->addr, k->name); + k = (void *)((uintptr_t)k + sizeof(uintptr_t) + strlen(k->name) + 1); + } + } + + return 0; +} + +static int shell_print(fs_node_t * tty, int argc, char * argv[]) { + + if (argc < 3) { + fprintf(tty, "print format_string symbol_name\n"); + return 1; + } + + char * format = argv[1]; + char * symbol = argv[2]; + int deref = 0; + + if (symbol[0] == '*') { + symbol = &symbol[1]; + deref = 1; + } + + void * addr = hashmap_get(modules_get_symbols(),symbol); + if (!addr) return 1; + + if (deref) { + fprintf(tty, format, addr); + } else { + fprintf(tty, format, *((uintptr_t *)addr)); + } + fprintf(tty, "\n"); + + return 0; +} + +static int shell_call(fs_node_t * tty, int argc, char * argv[]) { + + if (argc < 2) { + fprintf(tty, "call function_name\n"); + return 1; + } + + char * symbol = argv[1]; + + void (*addr)(void) = (void (*)(void))(uintptr_t)hashmap_get(modules_get_symbols(),symbol); + if (!addr) return 1; + + addr(); + + return 0; +} + +static int shell_modules(fs_node_t * tty, int argc, char * argv[]) { + list_t * hash_keys = hashmap_keys(modules_get_list()); + foreach(_key, hash_keys) { + char * key = (char *)_key->value; + module_data_t * mod_info = hashmap_get(modules_get_list(), key); + + fprintf(tty, "0x%x {.init=0x%x, .fini=0x%x} %s", + mod_info->bin_data, + mod_info->mod_info->initialize, + mod_info->mod_info->finalize, + mod_info->mod_info->name); + + if (mod_info->deps) { + unsigned int i = 0; + fprintf(tty, " Deps: "); + while (i < mod_info->deps_length) { + fprintf(tty, "%s ", &mod_info->deps[i]); + i += strlen(&mod_info->deps[i]) + 1; + } + } + + fprintf(tty, "\n"); + } + + return 0; +} + +static int shell_rdtsc(fs_node_t * tty, int argc, char * argv[]) { + uint64_t x; + asm volatile ("rdtsc" : "=A" (x)); + + fprintf(tty, "0x%x%x\n", (uint32_t)(x >> 32), (uint32_t)(x & 0xFFFFFFFF)); + + return 0; +} + +static int shell_mhz(fs_node_t * tty, int argc, char * argv[]) { + + uint64_t x, y; + + asm volatile ("rdtsc" : "=A" (x)); + + unsigned long s, ss; + relative_time(1, 0, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + + asm volatile ("rdtsc" : "=A" (y)); + + uint64_t diff = y - x; + uint32_t f = diff >> 15; + uint32_t mhz = f / 30; + + fprintf(tty, "%d MHz\n", mhz); + + return 0; +} + +/* + * Determine the size of a smart terminal that we don't have direct + * termios access to. This is done by sending a cursor-move command + * that will put the cursor into the lower right corner and then + * requesting the cursor position report. We then read and parse + * the position report. In the case where the terminal on the other + * end is actually dumb, we end up waiting for some input and + * then timing out. + * TODO with asyncio support, the timeout should actually work. + * consider also using an alarm (which I also don't have) + */ +static void divine_size(fs_node_t * dev, int * width, int * height) { + char tmp[100]; + int read = 0; + unsigned long start_tick = timer_ticks; + memset(tmp, 0, sizeof(tmp)); + /* Move cursor, Request position, Reset cursor */ + tty_set_unbuffered(dev); + fprintf(dev, "\033[1000;1000H\033[6n\033[H"); + while (1) { + char buf[1]; + int r = read_fs(dev, 0, 1, (unsigned char *)buf); + if (r > 0) { + if (buf[0] != 'R') { + if (read > 1) { + tmp[read-2] = buf[0]; + } + read++; + } else { + break; + } + } + if (timer_ticks - start_tick >= 2) { + /* + * We've timed out. This will only be triggered + * when we eventually receive something, though + */ + *width = 80; + *height = 23; + /* Clear and return */ + fprintf(dev, "\033[J"); + tty_set_buffered(dev); + return; + } + } + /* Clear */ + fprintf(dev, "\033[J"); + /* Break up the result into two strings */ + + for (unsigned int i = 0; i < strlen(tmp); i++) { + if (tmp[i] == ';') { + tmp[i] = '\0'; + break; + } + } + char * h = (char *)((uintptr_t)tmp + strlen(tmp)+1); + /* And then parse it into numbers */ + *height = atoi(tmp); + *width = atoi(h); + tty_set_buffered(dev); +} + +static int shell_divinesize(fs_node_t * tty, int argc, char * argv[]) { + struct winsize size = {0,0,0,0}; + + /* Attempt to divine the terminal size. Changing the window size after this will do bad things */ + int width, height; + divine_size(tty, &width, &height); + + fprintf(tty, "Identified size: %d x %d\n", width, height); + + size.ws_row = height; + size.ws_col = width; + + ioctl_fs(tty, TIOCSWINSZ, &size); + + return 0; +} + +static int shell_fix_mouse(fs_node_t * tty, int argc, char * argv[]) { + + fs_node_t * mouse = kopen("/dev/mouse", 0); + if (mouse) { + ioctl_fs(mouse, 1, NULL); + close_fs(mouse); + } + + return 0; +} + +static int shell_mount(fs_node_t * tty, int argc, char * argv[]) { + if (argc < 4) { + fprintf(tty, "Usage: %s type device mountpoint\n", argv[0]); + return 1; + } + + return -vfs_mount_type(argv[1], argv[2], argv[3]); +} + +static int shell_exit(fs_node_t * tty, int argc, char * argv[]) { + kexit(0); + return 0; +} + +static int shell_cursor_off(fs_node_t * tty, int argc, char * argv[]) { + outportb(0x3D4, 14); + outportb(0x3D5, 0xFF); + outportb(0x3D4, 15); + outportb(0x3D5, 0xFF); + return 0; +} + +extern pid_t trace_pid; +static int shell_debug_pid(fs_node_t * tty, int argc, char * argv[]) { + trace_pid = atoi(argv[1]); + return 0; +} + +static struct shell_command shell_commands[] = { + {"shell", &shell_create_userspace_shell, + "Runs a userspace shell on this tty."}, + {"login", &shell_replace_login, + "Replace the debug shell with /bin/login."}, + {"echo", &shell_echo, + "Prints arguments."}, + {"help", &shell_help, + "Prints a list of possible shell commands and their descriptions."}, + {"cd", &shell_cd, + "Change current directory."}, + {"ls", &shell_ls, + "List files in current or other directory."}, + {"cat", &shell_cat, + "Read a file to the console."}, + {"log", &shell_log, + "Configure serial debug logging."}, + {"pci", &shell_pci, + "Print PCI devices, as well as their names and BARs."}, + {"uid", &shell_uid, + "Change the effective user id of the shell."}, + {"mod", &shell_mod, + "[testing] Module loading."}, + {"symbols", &shell_symbols, + "Dump symbol table."}, + {"debug_pid", &shell_debug_pid, + "Set pid to trace syscalls for."}, + {"print", &shell_print, + "[dangerous] Print the value of a symbol using a format string."}, + {"call", &shell_call, + "[dangerous] Call a function by name."}, + {"modules", &shell_modules, + "Print names and addresses of all loaded modules."}, + {"divine-size", &shell_divinesize, + "Attempt to discover TTY size of serial."}, + {"fix-mouse", &shell_fix_mouse, + "Attempt to reset mouse device."}, + {"mount", &shell_mount, + "Mount a filesystemp."}, + {"rdtsc", &shell_rdtsc, + "Read the TSC, if available."}, + {"mhz", &shell_mhz, + "Use TSC to determine clock speed."}, + {"cursor-off", &shell_cursor_off, + "Disable VGA text mode cursor."}, + {"exit", &shell_exit, + "Quit the shell."}, + {NULL, NULL, NULL} +}; + +void debug_shell_install(struct shell_command * sh) { + hashmap_set(shell_commands_map, sh->name, sh); +} + +/* + * A TTY object to pass to the tasklets for handling + * serial-tty interaction. This probably shouldn't + * be done as tasklets - TTYs should just be able + * to wrap existing fs_nodes themselves, but that's + * a problem for another day. + */ +struct tty_o { + fs_node_t * node; + fs_node_t * tty; +}; + +/* + * These tasklets handle tty-serial interaction. + */ +static void debug_shell_handle_in(void * data, char * name) { + struct tty_o * tty = (struct tty_o *)data; + + while (1) { + uint8_t buf[1]; + int r = read_fs(tty->tty, 0, 1, (unsigned char *)buf); + write_fs(tty->node, 0, r, buf); + } +} + +static void debug_shell_handle_out(void * data, char * name) { + struct tty_o * tty = (struct tty_o *)data; + + while (1) { + uint8_t buf[1]; + int r = read_fs(tty->node, 0, 1, (unsigned char *)buf); + write_fs(tty->tty, 0, r, buf); + } +} + +static void debug_shell_actual(void * data, char * name) { + + current_process->image.entry = 0; + fs_node_t * tty = (fs_node_t *)data; + + /* Our prompt will include the version number of the current kernel */ + char version_number[1024]; + sprintf(version_number, __kernel_version_format, + __kernel_version_major, + __kernel_version_minor, + __kernel_version_lower, + __kernel_version_suffix); + + /* Initialize the shell commands map */ + int retval = 0; + + while (1) { + char command[512]; + + /* Print out the prompt */ + if (retval) { + fprintf(tty, "\033[1;34m%s-%s \033[1;31m%d\033[1;34m %s#\033[0m ", __kernel_name, version_number, retval, current_process->wd_name); + } else { + fprintf(tty, "\033[1;34m%s-%s %s#\033[0m ", __kernel_name, version_number, current_process->wd_name); + } + + /* Read a line */ + debug_shell_readline(tty, command, 511); + + char * arg = strdup(command); + char * argv[1024]; /* Command tokens (space-separated elements) */ + int argc = tokenize(arg, " ", argv); + + if (!argc) continue; + + /* Parse the command string */ + struct shell_command * sh = hashmap_get(shell_commands_map, argv[0]); + if (sh) { + retval = sh->function(tty, argc, argv); + } else { + fprintf(tty, "Unrecognized command: %s\n", argv[0]); + } + + free(arg); + } + +} + +/* + * Tasklet for managing the kernel serial console. + * This is basically a very simple shell, with access + * to some internal kernel commands, and (eventually) + * debugging routines. + */ +static void debug_shell_run(void * data, char * name) { + /* + * We will run on the first serial port. + * TODO detect that this failed + */ + fs_node_t * tty = kopen("/dev/ttyS0", 0); + + fs_node_t * fs_master; + fs_node_t * fs_slave; + + pty_create(NULL, &fs_master, &fs_slave); + + /* Attach the serial to the TTY interface */ + struct tty_o _tty = {.node = fs_master, .tty = tty}; + + create_kernel_tasklet(debug_shell_handle_in, "[kttydebug-in]", (void *)&_tty); + create_kernel_tasklet(debug_shell_handle_out, "[kttydebug-out]", (void *)&_tty); + + /* Set the device to be the actual TTY slave */ + tty = fs_slave; + + fs_master->refcount = -1; + fs_slave->refcount = -1; + + current_process->fds->entries[0] = tty; + current_process->fds->entries[1] = tty; + current_process->fds->entries[2] = tty; + current_process->fds->length = 3; + + tty_set_vintr(tty, 0x02); + + fprintf(tty, "\n\n" + "Serial debug console started.\n" + "Type `help` for a list of commands.\n" + "To access a userspace shell, type `shell`.\n" + "Use ^B to send SIGINT instead of ^C.\n" + "\n"); + + debug_shell_actual(tty, name); +} + +int debug_shell_start(void) { + /* Setup shell commands */ + shell_commands_map = hashmap_create(10); + struct shell_command * sh = &shell_commands[0]; + while (sh->name) { + hashmap_set(shell_commands_map, sh->name, sh); + sh++; + } + + debug_hook = debug_shell_actual; + + if (args_present("kdebug")) { + int i = create_kernel_tasklet(debug_shell_run, "[kttydebug]", NULL); + debug_print(NOTICE, "Started tasklet with pid=%d", i); + } + + return 0; +} + +int debug_shell_stop(void) { + debug_print(NOTICE, "Tried to unload debug shell, but debug shell has no real shutdown routine. Don't do that!"); + return 0; +} + +MODULE_DEF(debugshell, debug_shell_start, debug_shell_stop); +MODULE_DEPENDS(serial); diff --git a/modules/dospart.c b/modules/dospart.c new file mode 100644 index 00000000..d955326a --- /dev/null +++ b/modules/dospart.c @@ -0,0 +1,130 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include + +#define SECTORSIZE 512 + +static mbr_t mbr; + +struct dos_partition_entry { + fs_node_t * device; + partition_t partition; +}; + +static uint32_t read_part(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + struct dos_partition_entry * device = (struct dos_partition_entry *)node->device; + + if (offset > device->partition.sector_count * SECTORSIZE) { + debug_print(WARNING, "Read beyond partition!"); + return 0; + } + + if (offset + size > device->partition.sector_count * SECTORSIZE) { + size = device->partition.sector_count * SECTORSIZE - offset; + debug_print(WARNING, "Tried to read past end of partition, clamped to %d", size); + } + + return read_fs(device->device, offset + device->partition.lba_first_sector * SECTORSIZE, size, buffer); +} + +static uint32_t write_part(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + struct dos_partition_entry * device = (struct dos_partition_entry *)node->device; + + if (offset > device->partition.sector_count * SECTORSIZE) { + return 0; + } + + if (offset + size > device->partition.sector_count * SECTORSIZE) { + size = device->partition.sector_count * SECTORSIZE - offset; + } + + return write_fs(device->device, offset + device->partition.lba_first_sector * SECTORSIZE, size, buffer); +} + +static void open_part(fs_node_t * node, unsigned int flags) { + return; +} + +static void close_part(fs_node_t * node) { + return; +} + +static fs_node_t * dospart_device_create(int i, fs_node_t * dev, partition_t * part) { + + vfs_lock(dev); + + struct dos_partition_entry * device = malloc(sizeof(struct dos_partition_entry)); + memcpy(&device->partition, part, sizeof(partition_t)); + device->device = dev; + + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + sprintf(fnode->name, "dospart%d", i); + fnode->device = device; + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0660; + fnode->length = device->partition.sector_count * SECTORSIZE; /* TODO */ + fnode->flags = FS_BLOCKDEVICE; + fnode->read = read_part; + fnode->write = write_part; + fnode->open = open_part; + fnode->close = close_part; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; /* TODO, identify, etc? */ + return fnode; +} + +static int read_partition_map(char * name) { + fs_node_t * device = kopen(name, 0); + if (!device) return 1; + + read_fs(device, 0, SECTORSIZE, (uint8_t *)&mbr); + + if (mbr.signature[0] == 0x55 && mbr.signature[1] == 0xAA) { + debug_print(INFO, "Partition table found."); + + for (int i = 0; i < 4; ++i) { + if (mbr.partitions[i].status & 0x80) { + debug_print(NOTICE, "Partition #%d: @%d+%d", i+1, mbr.partitions[i].lba_first_sector, mbr.partitions[i].sector_count); + fs_node_t * node = dospart_device_create(i, device, &mbr.partitions[i]); + + char tmp[64]; + sprintf(tmp, "%s%d", name, i); + vfs_mount(tmp, node); + } else { + debug_print(NOTICE, "Partition #%d: inactive", i+1); + } + } + } else { + debug_print(NOTICE, "No partition table on %s", name); + } + + return 0; +} + +static int dospart_initialize(void) { + for (char l = 'a'; l < 'z'; ++l) { + char name[64]; + sprintf(name, "/dev/hd%c", l); + if (read_partition_map(name)) { + break; + } + } + return 0; +} + +static int dospart_finalize(void) { + return 0; +} + +MODULE_DEF(dospart, dospart_initialize, dospart_finalize); diff --git a/modules/e1000.c b/modules/e1000.c new file mode 100644 index 00000000..5bca0d60 --- /dev/null +++ b/modules/e1000.c @@ -0,0 +1,435 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2017 Kevin Lange + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static uint32_t e1000_device_pci = 0x00000000; +static int e1000_irq = 0; +static uintptr_t mem_base = 0; +static int has_eeprom = 0; +static uint8_t mac[6]; +static int rx_index = 0; +static int tx_index = 0; + +static list_t * net_queue = NULL; +static spin_lock_t net_queue_lock = { 0 }; +static list_t * rx_wait; + +static uint32_t mmio_read32(uintptr_t addr) { + return *((volatile uint32_t*)(addr)); +} +static void mmio_write32(uintptr_t addr, uint32_t val) { + (*((volatile uint32_t*)(addr))) = val; +} + +static void write_command(uint16_t addr, uint32_t val) { + mmio_write32(mem_base + addr, val); +} + +static uint32_t read_command(uint16_t addr) { + return mmio_read32(mem_base + addr); +} + +#define E1000_NUM_RX_DESC 32 +#define E1000_NUM_TX_DESC 8 + +struct rx_desc { + volatile uint64_t addr; + volatile uint16_t length; + volatile uint16_t checksum; + volatile uint8_t status; + volatile uint8_t errors; + volatile uint16_t special; +} __attribute__((packed)); /* this looks like it should pack fine as-is */ + +struct tx_desc { + volatile uint64_t addr; + volatile uint16_t length; + volatile uint8_t cso; + volatile uint8_t cmd; + volatile uint8_t status; + volatile uint8_t css; + volatile uint16_t special; +} __attribute__((packed)); + +static uint8_t * rx_virt[E1000_NUM_RX_DESC]; +static uint8_t * tx_virt[E1000_NUM_TX_DESC]; +static struct rx_desc * rx; +static struct tx_desc * tx; +static uintptr_t rx_phys; +static uintptr_t tx_phys; + +static void enqueue_packet(void * buffer) { + spin_lock(net_queue_lock); + list_insert(net_queue, buffer); + spin_unlock(net_queue_lock); +} + +static struct ethernet_packet * dequeue_packet(void) { + while (!net_queue->length) { + sleep_on(rx_wait); + } + + spin_lock(net_queue_lock); + node_t * n = list_dequeue(net_queue); + void* value = n->value; + free(n); + spin_unlock(net_queue_lock); + + return value; +} + +static uint8_t* get_mac() { + return mac; +} + +#define E1000_REG_CTRL 0x0000 +#define E1000_REG_STATUS 0x0008 +#define E1000_REG_EEPROM 0x0014 +#define E1000_REG_CTRL_EXT 0x0018 + +#define E1000_REG_RCTRL 0x0100 +#define E1000_REG_RXDESCLO 0x2800 +#define E1000_REG_RXDESCHI 0x2804 +#define E1000_REG_RXDESCLEN 0x2808 +#define E1000_REG_RXDESCHEAD 0x2810 +#define E1000_REG_RXDESCTAIL 0x2818 + +#define E1000_REG_TCTRL 0x0400 +#define E1000_REG_TXDESCLO 0x3800 +#define E1000_REG_TXDESCHI 0x3804 +#define E1000_REG_TXDESCLEN 0x3808 +#define E1000_REG_TXDESCHEAD 0x3810 +#define E1000_REG_TXDESCTAIL 0x3818 + +#define RCTL_EN (1 << 1) /* Receiver Enable */ +#define RCTL_SBP (1 << 2) /* Store Bad Packets */ +#define RCTL_UPE (1 << 3) /* Unicast Promiscuous Enabled */ +#define RCTL_MPE (1 << 4) /* Multicast Promiscuous Enabled */ +#define RCTL_LPE (1 << 5) /* Long Packet Reception Enable */ +#define RCTL_LBM_NONE (0 << 6) /* No Loopback */ +#define RCTL_LBM_PHY (3 << 6) /* PHY or external SerDesc loopback */ +#define RTCL_RDMTS_HALF (0 << 8) /* Free Buffer Threshold is 1/2 of RDLEN */ +#define RTCL_RDMTS_QUARTER (1 << 8) /* Free Buffer Threshold is 1/4 of RDLEN */ +#define RTCL_RDMTS_EIGHTH (2 << 8) /* Free Buffer Threshold is 1/8 of RDLEN */ +#define RCTL_MO_36 (0 << 12) /* Multicast Offset - bits 47:36 */ +#define RCTL_MO_35 (1 << 12) /* Multicast Offset - bits 46:35 */ +#define RCTL_MO_34 (2 << 12) /* Multicast Offset - bits 45:34 */ +#define RCTL_MO_32 (3 << 12) /* Multicast Offset - bits 43:32 */ +#define RCTL_BAM (1 << 15) /* Broadcast Accept Mode */ +#define RCTL_VFE (1 << 18) /* VLAN Filter Enable */ +#define RCTL_CFIEN (1 << 19) /* Canonical Form Indicator Enable */ +#define RCTL_CFI (1 << 20) /* Canonical Form Indicator Bit Value */ +#define RCTL_DPF (1 << 22) /* Discard Pause Frames */ +#define RCTL_PMCF (1 << 23) /* Pass MAC Control Frames */ +#define RCTL_SECRC (1 << 26) /* Strip Ethernet CRC */ + +#define RCTL_BSIZE_256 (3 << 16) +#define RCTL_BSIZE_512 (2 << 16) +#define RCTL_BSIZE_1024 (1 << 16) +#define RCTL_BSIZE_2048 (0 << 16) +#define RCTL_BSIZE_4096 ((3 << 16) | (1 << 25)) +#define RCTL_BSIZE_8192 ((2 << 16) | (1 << 25)) +#define RCTL_BSIZE_16384 ((1 << 16) | (1 << 25)) + +#define TCTL_EN (1 << 1) /* Transmit Enable */ +#define TCTL_PSP (1 << 3) /* Pad Short Packets */ +#define TCTL_CT_SHIFT 4 /* Collision Threshold */ +#define TCTL_COLD_SHIFT 12 /* Collision Distance */ +#define TCTL_SWXOFF (1 << 22) /* Software XOFF Transmission */ +#define TCTL_RTLC (1 << 24) /* Re-transmit on Late Collision */ + +#define CMD_EOP (1 << 0) /* End of Packet */ +#define CMD_IFCS (1 << 1) /* Insert FCS */ +#define CMD_IC (1 << 2) /* Insert Checksum */ +#define CMD_RS (1 << 3) /* Report Status */ +#define CMD_RPS (1 << 4) /* Report Packet Sent */ +#define CMD_VLE (1 << 6) /* VLAN Packet Enable */ +#define CMD_IDE (1 << 7) /* Interrupt Delay Enable */ + +static int eeprom_detect(void) { + + write_command(E1000_REG_EEPROM, 1); + + for (int i = 0; i < 100000 && !has_eeprom; ++i) { + uint32_t val = read_command(E1000_REG_EEPROM); + if (val & 0x10) has_eeprom = 1; + } + + return 0; +} + +static uint16_t eeprom_read(uint8_t addr) { + uint32_t temp = 0; + write_command(E1000_REG_EEPROM, 1 | ((uint32_t)(addr) << 8)); + while (!((temp = read_command(E1000_REG_EEPROM)) & (1 << 4))); + return (uint16_t)((temp >> 16) & 0xFFFF); +} + + +static void find_e1000(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + if ((vendorid == 0x8086) && (deviceid == 0x100e || deviceid == 0x1004 || deviceid == 0x100f)) { + *((uint32_t *)extra) = device; + } +} + +static void read_mac(void) { + if (has_eeprom) { + uint32_t t; + t = eeprom_read(0); + mac[0] = t & 0xFF; + mac[1] = t >> 8; + t = eeprom_read(1); + mac[2] = t & 0xFF; + mac[3] = t >> 8; + t = eeprom_read(2); + mac[4] = t & 0xFF; + mac[5] = t >> 8; + } else { + uint8_t * mac_addr = (uint8_t *)(mem_base + 0x5400); + for (int i = 0; i < 6; ++i) { + mac[i] = mac_addr[i]; + } + } +} + +static int irq_handler(struct regs *r) { + + uint32_t status = read_command(0xc0); + + irq_ack(e1000_irq); + + if (!status) { + return 0; + } + + if (status & 0x04) { + /* Start link */ + debug_print(NOTICE, "start link"); + } else if (status & 0x10) { + /* ?? */ + } else if (status & ((1 << 6) | (1 << 7))) { + /* receive packet */ + do { + rx_index = read_command(E1000_REG_RXDESCTAIL); + if (rx_index == (int)read_command(E1000_REG_RXDESCHEAD)) return 1; + rx_index = (rx_index + 1) % E1000_NUM_RX_DESC; + if (rx[rx_index].status & 0x01) { + uint8_t * pbuf = (uint8_t *)rx_virt[rx_index]; + uint16_t plen = rx[rx_index].length; + + void * packet = malloc(plen); + memcpy(packet, pbuf, plen); + + rx[rx_index].status = 0; + + enqueue_packet(packet); + + write_command(E1000_REG_RXDESCTAIL, rx_index); + } else { + break; + } + } while (1); + wakeup_queue(rx_wait); + } + + return 1; +} + +static void send_packet(uint8_t* payload, size_t payload_size) { + tx_index = read_command(E1000_REG_TXDESCTAIL); + debug_print(NOTICE,"sending packet 0x%x, %d desc[%d]", payload, payload_size, tx_index); + + memcpy(tx_virt[tx_index], payload, payload_size); + tx[tx_index].length = payload_size; + tx[tx_index].cmd = CMD_EOP | CMD_IFCS | CMD_RS; //| CMD_RPS; + tx[tx_index].status = 0; + + tx_index = (tx_index + 1) % E1000_NUM_TX_DESC; + write_command(E1000_REG_TXDESCTAIL, tx_index); +} + +static void init_rx(void) { + + write_command(E1000_REG_RXDESCLO, rx_phys); + write_command(E1000_REG_RXDESCHI, 0); + + write_command(E1000_REG_RXDESCLEN, E1000_NUM_RX_DESC * sizeof(struct rx_desc)); + + write_command(E1000_REG_RXDESCHEAD, 0); + write_command(E1000_REG_RXDESCTAIL, E1000_NUM_RX_DESC - 1); + + rx_index = 0; + + write_command(E1000_REG_RCTRL, + RCTL_EN | + (read_command(E1000_REG_RCTRL) & (~((1 << 17) | (1 << 16))))); + +} + +static void init_tx(void) { + + + write_command(E1000_REG_TXDESCLO, tx_phys); + write_command(E1000_REG_TXDESCHI, 0); + + write_command(E1000_REG_TXDESCLEN, E1000_NUM_TX_DESC * sizeof(struct tx_desc)); + + write_command(E1000_REG_TXDESCHEAD, 0); + write_command(E1000_REG_TXDESCTAIL, 0); + + tx_index = 0; + + write_command(E1000_REG_TCTRL, + TCTL_EN | + TCTL_PSP | + read_command(E1000_REG_TCTRL)); +} + + +static void e1000_init(void * data, char * name) { + + uint16_t command_reg = pci_read_field(e1000_device_pci, PCI_COMMAND, 2); + command_reg |= (1 << 2); + command_reg |= (1 << 0); + pci_write_field(e1000_device_pci, PCI_COMMAND, 2, command_reg); + + debug_print(NOTICE, "mem base: 0x%x", mem_base); + + eeprom_detect(); + debug_print(NOTICE, "has_eeprom = %d", has_eeprom); + read_mac(); + + debug_print(NOTICE, "device mac %2x:%2x:%2x:%2x:%2x:%2x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + /* initialize */ + write_command(E1000_REG_CTRL, (1 << 26)); + + /* wait */ + unsigned long s, ss; + relative_time(0, 10, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + debug_print(NOTICE, "back from sleep"); + + uint32_t status = read_command(E1000_REG_CTRL); + status |= (1 << 5); /* set auto speed detection */ + status |= (1 << 6); /* set link up */ + status &= ~(1 << 3); /* unset link reset */ + status &= ~(1 << 31); /* unset phy reset */ + status &= ~(1 << 7); /* unset invert loss-of-signal */ + write_command(E1000_REG_CTRL, status); + + /* Disables flow control */ + write_command(0x0028, 0); + write_command(0x002c, 0); + write_command(0x0030, 0); + write_command(0x0170, 0); + + /* Unset flow control */ + status = read_command(E1000_REG_CTRL); + status &= ~(1 << 30); + write_command(E1000_REG_CTRL, status); + + relative_time(0, 10, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + + net_queue = list_create(); + rx_wait = list_create(); + + e1000_irq = pci_read_field(e1000_device_pci, PCI_INTERRUPT_LINE, 1); + irq_install_handler(e1000_irq, irq_handler); + + debug_print(NOTICE, "Binding interrupt %d", e1000_irq); + + for (int i = 0; i < 128; ++i) { + write_command(0x5200 + i * 4, 0); + } + + for (int i = 0; i < 64; ++i) { + write_command(0x4000 + i * 4, 0); + } + +#if 0 + /* This would rewrite the MAC address... */ + write_command(0x5400, *(uint32_t*)(&mac[0])); + write_command(0x5404, *(uint16_t*)(&mac[4])); + write_command(0x5404, read_command(0x5404) | (1 << 31)); +#endif + + write_command(E1000_REG_RCTRL, (1 << 4)); + + init_rx(); + init_tx(); + + /* Twiddle interrupts */ + write_command(0x00D0, 0xFF); + write_command(0x00D8, 0xFF); + write_command(0x00D0,(1 << 2) | (1 << 6) | (1 << 7) | (1 << 1) | (1 << 0)); + + relative_time(0, 10, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + + int link_is_up = (read_command(E1000_REG_STATUS) & (1 << 1)); + debug_print(NOTICE,"e1000 done. has_eeprom = %d, link is up = %d, irq=%d", has_eeprom, link_is_up, e1000_irq); + + init_netif_funcs(get_mac, dequeue_packet, send_packet, "Intel E1000"); +} + +static int init(void) { + pci_scan(&find_e1000, -1, &e1000_device_pci); + + if (!e1000_device_pci) { + debug_print(WARNING, "No e1000 device found."); + return 1; + } + + /* This seems to always be memory mapped on important devices. */ + mem_base = pci_read_field(e1000_device_pci, PCI_BAR0, 4) & 0xFFFFFFF0; + + for (size_t x = 0; x < 0x10000; x += 0x1000) { + uintptr_t addr = (mem_base & 0xFFFFF000) + x; + dma_frame(get_page(addr, 1, kernel_directory), 1, 1, addr); + } + + rx = (void*)kvmalloc_p(sizeof(struct rx_desc) * E1000_NUM_RX_DESC + 16, &rx_phys); + + for (int i = 0; i < E1000_NUM_RX_DESC; ++i) { + rx_virt[i] = (void*)kvmalloc_p(8192 + 16, (uint32_t *)&rx[i].addr); + debug_print(INFO, "rx[%d] 0x%x → 0x%x", i, rx_virt[i], (uint32_t)rx[i].addr); + rx[i].status = 0; + } + + tx = (void*)kvmalloc_p(sizeof(struct tx_desc) * E1000_NUM_TX_DESC + 16, &tx_phys); + + for (int i = 0; i < E1000_NUM_TX_DESC; ++i) { + tx_virt[i] = (void*)kvmalloc_p(8192+16, (uint32_t *)&tx[i].addr); + debug_print(INFO, "tx[%d] 0x%x → 0x%x", i, tx_virt[i], (uint32_t)tx[i].addr); + tx[i].status = 0; + tx[i].cmd = (1 << 0); + } + + + create_kernel_tasklet(e1000_init, "[e1000]", NULL); + + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(e1000, init, fini); +MODULE_DEPENDS(net); diff --git a/modules/ext2.c b/modules/ext2.c new file mode 100644 index 00000000..46ffbd3e --- /dev/null +++ b/modules/ext2.c @@ -0,0 +1,1651 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXT2_BGD_BLOCK 2 + +#define E_SUCCESS 0 +#define E_BADBLOCK 1 +#define E_NOSPACE 2 +#define E_BADPARENT 3 + +#undef _symlink +#define _symlink(inode) ((char *)(inode)->block) + +/* + * EXT2 filesystem object + */ +typedef struct { + ext2_superblock_t * superblock; /* Device superblock, contains important information */ + ext2_bgdescriptor_t * block_groups; /* Block Group Descriptor / Block groups */ + fs_node_t * root_node; /* Root FS node (attached to mountpoint) */ + + fs_node_t * block_device; /* Block device node XXX unused */ + + unsigned int block_size; /* Size of one block */ + unsigned int pointers_per_block; /* Number of pointers that fit in a block */ + unsigned int inodes_per_group; /* Number of inodes in a "group" */ + unsigned int block_group_count; /* Number of blocks groups */ + + ext2_disk_cache_entry_t * disk_cache; /* Dynamically allocated array of cache entries */ + unsigned int cache_entries; /* Size of ->disk_cache */ + unsigned int cache_time; /* "timer" that increments with each cache read/write */ + + spin_lock_t lock; /* Synchronization lock point */ + + uint8_t bgd_block_span; + uint8_t bgd_offset; + unsigned int inode_size; + + uint8_t * cache_data; + + int flags; +} ext2_fs_t; + +#define EXT2_FLAG_NOCACHE 0x0001 + +/* + * These macros were used in the original toaru ext2 driver. + * They make referring to some of the core parts of the drive a bit easier. + */ +#define BGDS (this->block_group_count) +#define SB (this->superblock) +#define BGD (this->block_groups) +#define RN (this->root_node) +#define DC (this->disk_cache) + +/* + * These macros deal with the block group descriptor bitmap + */ +#define BLOCKBIT(n) (bg_buffer[((n) >> 3)] & (1 << (((n) % 8)))) +#define BLOCKBYTE(n) (bg_buffer[((n) >> 3)]) +#define SETBIT(n) (1 << (((n) % 8))) + +static uint32_t node_from_file(ext2_fs_t * this, ext2_inodetable_t *inode, ext2_dir_t *direntry, fs_node_t *fnode); +static uint32_t ext2_root(ext2_fs_t * this, ext2_inodetable_t *inode, fs_node_t *fnode); +static ext2_inodetable_t * read_inode(ext2_fs_t * this, uint32_t inode); +static void refresh_inode(ext2_fs_t * this, ext2_inodetable_t * inodet, uint32_t inode); +static int write_inode(ext2_fs_t * this, ext2_inodetable_t *inode, uint32_t index); +static fs_node_t * finddir_ext2(fs_node_t *node, char *name); +static unsigned int allocate_block(ext2_fs_t * this); + +/** + * ext2->get_cache_time Increment and return the current cache time + * + * @returns Current cache time + */ +static unsigned int get_cache_time(ext2_fs_t * this) { + return this->cache_time++; +} + +/** + * ext2->cache_flush_dirty Flush dirty cache entry to the disk. + * + * @param ent_no Cache entry to dump + * @returns Error code or E_SUCCESS + */ +static int cache_flush_dirty(ext2_fs_t * this, unsigned int ent_no) { + write_fs(this->block_device, (DC[ent_no].block_no) * this->block_size, this->block_size, (uint8_t *)(DC[ent_no].block)); + DC[ent_no].dirty = 0; + + return E_SUCCESS; +} + +/** + * ext2->rewrite_superblock Rewrite the superblock. + * + * Superblocks are a bit different from other blocks, as they are always in the same place, + * regardless of what the filesystem block size is. This doesn't work well with our setup, + * so we need to special-case it. + */ +static int rewrite_superblock(ext2_fs_t * this) { + write_fs(this->block_device, 1024, sizeof(ext2_superblock_t), (uint8_t *)SB); + return E_SUCCESS; +} + +/** + * ext2->read_block Read a block from the block device associated with this filesystem. + * + * The read block will be copied into the buffer pointed to by `buf`. + * + * @param block_no Number of block to read. + * @param buf Where to put the data read. + * @returns Error code or E_SUCCESS + */ +static int read_block(ext2_fs_t * this, unsigned int block_no, uint8_t * buf) { + /* 0 is an invalid block number. So is anything beyond the total block count, but we can't check that. */ + if (!block_no) { + return E_BADBLOCK; + } + + /* This operation requires the filesystem lock to be obtained */ + spin_lock(this->lock); + + /* We can make reads without a cache in place. */ + if (!DC) { + /* In such cases, we read directly from the block device */ + read_fs(this->block_device, block_no * this->block_size, this->block_size, (uint8_t *)buf); + /* We are done, release the lock */ + spin_unlock(this->lock); + /* And return SUCCESS */ + return E_SUCCESS; + } + + /* + * Search the cache for this entry + * We'll look for the oldest entry, too. + */ + int oldest = -1; + unsigned int oldest_age = UINT32_MAX; + for (unsigned int i = 0; i < this->cache_entries; ++i) { + if (DC[i].block_no == block_no) { + /* We found it! Update usage times */ + DC[i].last_use = get_cache_time(this); + /* Read the block */ + memcpy(buf, DC[i].block, this->block_size); + /* Release the lock */ + spin_unlock(this->lock); + /* Success! */ + return E_SUCCESS; + } + if (DC[i].last_use < oldest_age) { + /* We found an older block, remember this. */ + oldest = i; + oldest_age = DC[i].last_use; + } + } + + /* + * At this point, we did not find this block in the cache. + * We are going to replace the oldest entry with this new one. + */ + + /* We'll start by flushing the block if it was dirty. */ + if (DC[oldest].dirty) { + cache_flush_dirty(this, oldest); + } + + /* Then we'll read the new one */ + read_fs(this->block_device, block_no * this->block_size, this->block_size, (uint8_t *)DC[oldest].block); + + /* And copy the results to the output buffer */ + memcpy(buf, DC[oldest].block, this->block_size); + + /* And update the cache entry to point to the new block */ + DC[oldest].block_no = block_no; + DC[oldest].last_use = get_cache_time(this); + DC[oldest].dirty = 0; + + /* Release the lock */ + spin_unlock(this->lock); + + /* And return success */ + return E_SUCCESS; +} + +/** + * ext2->write_block Write a block to the block device. + * + * @param block_no Block to write + * @param buf Data in the block + * @returns Error code or E_SUCCESSS + */ +static int write_block(ext2_fs_t * this, unsigned int block_no, uint8_t *buf) { + if (!block_no) { + debug_print(ERROR, "Attempted to write to block #0. Enable tracing and retry this operation."); + debug_print(ERROR, "Your file system is most likely corrupted now."); + return E_BADBLOCK; + } + + /* This operation requires the filesystem lock */ + spin_lock(this->lock); + + if (!DC) { + write_fs(this->block_device, block_no * this->block_size, this->block_size, buf); + spin_unlock(this->lock); + return E_SUCCESS; + } + + /* Find the entry in the cache */ + int oldest = -1; + unsigned int oldest_age = UINT32_MAX; + for (unsigned int i = 0; i < this->cache_entries; ++i) { + if (DC[i].block_no == block_no) { + /* We found it. Update the cache entry */ + DC[i].last_use = get_cache_time(this); + DC[i].dirty = 1; + memcpy(DC[i].block, buf, this->block_size); + spin_unlock(this->lock); + return E_SUCCESS; + } + if (DC[i].last_use < oldest_age) { + /* Keep track of the oldest entry */ + oldest = i; + oldest_age = DC[i].last_use; + } + } + + /* We did not find this element in the cache, so make room. */ + if (DC[oldest].dirty) { + /* Flush the oldest entry */ + cache_flush_dirty(this, oldest); + } + + /* Update the entry */ + memcpy(DC[oldest].block, buf, this->block_size); + DC[oldest].block_no = block_no; + DC[oldest].last_use = get_cache_time(this); + DC[oldest].dirty = 1; + + /* Release the lock */ + spin_unlock(this->lock); + + /* We're done. */ + return E_SUCCESS; +} + +static unsigned int ext2_sync(ext2_fs_t * this) { + if (!this->disk_cache) return 0; + + /* This operation requires the filesystem lock */ + spin_lock(this->lock); + + /* Flush each cache entry. */ + for (unsigned int i = 0; i < this->cache_entries; ++i) { + if (DC[i].dirty) { + cache_flush_dirty(this, i); + } + } + + /* Release the lock */ + spin_unlock(this->lock); + + return 0; +} + +/** + * ext2->set_block_number Set the "real" block number for a given "inode" block number. + * + * @param inode Inode to operate on + * @param iblock Block offset within the inode + * @param rblock Real block number + * @returns Error code or E_SUCCESS + */ +static unsigned int set_block_number(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int inode_no, unsigned int iblock, unsigned int rblock) { + + unsigned int p = this->pointers_per_block; + + /* We're going to do some crazy math in a bit... */ + unsigned int a, b, c, d, e, f, g; + + uint8_t * tmp; + + if (iblock < EXT2_DIRECT_BLOCKS) { + inode->block[iblock] = rblock; + return E_SUCCESS; + } else if (iblock < EXT2_DIRECT_BLOCKS + p) { + /* XXX what if inode->block[EXT2_DIRECT_BLOCKS] isn't set? */ + if (!inode->block[EXT2_DIRECT_BLOCKS]) { + unsigned int block_no = allocate_block(this); + if (!block_no) return E_NOSPACE; + inode->block[EXT2_DIRECT_BLOCKS] = block_no; + write_inode(this, inode, inode_no); + } + tmp = malloc(this->block_size); + read_block(this, inode->block[EXT2_DIRECT_BLOCKS], (uint8_t *)tmp); + + ((uint32_t *)tmp)[iblock - EXT2_DIRECT_BLOCKS] = rblock; + write_block(this, inode->block[EXT2_DIRECT_BLOCKS], (uint8_t *)tmp); + + free(tmp); + return E_SUCCESS; + } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p) { + a = iblock - EXT2_DIRECT_BLOCKS; + b = a - p; + c = b / p; + d = b - c * p; + + if (!inode->block[EXT2_DIRECT_BLOCKS+1]) { + unsigned int block_no = allocate_block(this); + if (!block_no) return E_NOSPACE; + inode->block[EXT2_DIRECT_BLOCKS+1] = block_no; + write_inode(this, inode, inode_no); + } + + tmp = malloc(this->block_size); + read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 1], (uint8_t *)tmp); + + if (!((uint32_t *)tmp)[c]) { + unsigned int block_no = allocate_block(this); + if (!block_no) goto no_space_free; + ((uint32_t *)tmp)[c] = block_no; + write_block(this, inode->block[EXT2_DIRECT_BLOCKS + 1], (uint8_t *)tmp); + } + + uint32_t nblock = ((uint32_t *)tmp)[c]; + read_block(this, nblock, (uint8_t *)tmp); + + ((uint32_t *)tmp)[d] = rblock; + write_block(this, nblock, (uint8_t *)tmp); + + free(tmp); + return E_SUCCESS; + } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p + p) { + a = iblock - EXT2_DIRECT_BLOCKS; + b = a - p; + c = b - p * p; + d = c / (p * p); + e = c - d * p * p; + f = e / p; + g = e - f * p; + + if (!inode->block[EXT2_DIRECT_BLOCKS+2]) { + unsigned int block_no = allocate_block(this); + if (!block_no) return E_NOSPACE; + inode->block[EXT2_DIRECT_BLOCKS+2] = block_no; + write_inode(this, inode, inode_no); + } + + tmp = malloc(this->block_size); + read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 2], (uint8_t *)tmp); + + if (!((uint32_t *)tmp)[d]) { + unsigned int block_no = allocate_block(this); + if (!block_no) goto no_space_free; + ((uint32_t *)tmp)[d] = block_no; + write_block(this, inode->block[EXT2_DIRECT_BLOCKS + 2], (uint8_t *)tmp); + } + + uint32_t nblock = ((uint32_t *)tmp)[d]; + read_block(this, nblock, (uint8_t *)tmp); + + if (!((uint32_t *)tmp)[f]) { + unsigned int block_no = allocate_block(this); + if (!block_no) goto no_space_free; + ((uint32_t *)tmp)[f] = block_no; + write_block(this, nblock, (uint8_t *)tmp); + } + + nblock = ((uint32_t *)tmp)[f]; + read_block(this, nblock, (uint8_t *)tmp); + + ((uint32_t *)tmp)[g] = nblock; + write_block(this, nblock, (uint8_t *)tmp); + + free(tmp); + return E_SUCCESS; + } + + debug_print(CRITICAL, "EXT2 driver tried to write to a block number that was too high (%d)", rblock); + return E_BADBLOCK; +no_space_free: + free(tmp); + return E_NOSPACE; +} + +/** + * ext2->get_block_number Given an inode block number, get the real block number. + * + * @param inode Inode to operate on + * @param iblock Block offset within the inode + * @returns Real block number + */ +static unsigned int get_block_number(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int iblock) { + + unsigned int p = this->pointers_per_block; + + /* We're going to do some crazy math in a bit... */ + unsigned int a, b, c, d, e, f, g; + + uint8_t * tmp; + + if (iblock < EXT2_DIRECT_BLOCKS) { + return inode->block[iblock]; + } else if (iblock < EXT2_DIRECT_BLOCKS + p) { + /* XXX what if inode->block[EXT2_DIRECT_BLOCKS] isn't set? */ + tmp = malloc(this->block_size); + read_block(this, inode->block[EXT2_DIRECT_BLOCKS], (uint8_t *)tmp); + + unsigned int out = ((uint32_t *)tmp)[iblock - EXT2_DIRECT_BLOCKS]; + free(tmp); + return out; + } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p) { + a = iblock - EXT2_DIRECT_BLOCKS; + b = a - p; + c = b / p; + d = b - c * p; + + tmp = malloc(this->block_size); + read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 1], (uint8_t *)tmp); + + uint32_t nblock = ((uint32_t *)tmp)[c]; + read_block(this, nblock, (uint8_t *)tmp); + + unsigned int out = ((uint32_t *)tmp)[d]; + free(tmp); + return out; + } else if (iblock < EXT2_DIRECT_BLOCKS + p + p * p + p) { + a = iblock - EXT2_DIRECT_BLOCKS; + b = a - p; + c = b - p * p; + d = c / (p * p); + e = c - d * p * p; + f = e / p; + g = e - f * p; + + tmp = malloc(this->block_size); + read_block(this, inode->block[EXT2_DIRECT_BLOCKS + 2], (uint8_t *)tmp); + + uint32_t nblock = ((uint32_t *)tmp)[d]; + read_block(this, nblock, (uint8_t *)tmp); + + nblock = ((uint32_t *)tmp)[f]; + read_block(this, nblock, (uint8_t *)tmp); + + unsigned int out = ((uint32_t *)tmp)[g]; + free(tmp); + return out; + } + + debug_print(CRITICAL, "EXT2 driver tried to read to a block number that was too high (%d)", iblock); + + return 0; +} + +static int write_inode(ext2_fs_t * this, ext2_inodetable_t *inode, uint32_t index) { + uint32_t group = index / this->inodes_per_group; + if (group > BGDS) { + return E_BADBLOCK; + } + + uint32_t inode_table_block = BGD[group].inode_table; + index -= group * this->inodes_per_group; + uint32_t block_offset = ((index - 1) * this->inode_size) / this->block_size; + uint32_t offset_in_block = (index - 1) - block_offset * (this->block_size / this->inode_size); + + ext2_inodetable_t *inodet = malloc(this->block_size); + /* Read the current table block */ + read_block(this, inode_table_block + block_offset, (uint8_t *)inodet); + memcpy((uint8_t *)((uint32_t)inodet + offset_in_block * this->inode_size), inode, this->inode_size); + write_block(this, inode_table_block + block_offset, (uint8_t *)inodet); + free(inodet); + + return E_SUCCESS; +} + +static unsigned int allocate_block(ext2_fs_t * this) { + unsigned int block_no = 0; + unsigned int block_offset = 0; + unsigned int group = 0; + uint8_t * bg_buffer = malloc(this->block_size); + + for (unsigned int i = 0; i < BGDS; ++i) { + if (BGD[i].free_blocks_count > 0) { + read_block(this, BGD[i].block_bitmap, (uint8_t *)bg_buffer); + while (BLOCKBIT(block_offset)) { + ++block_offset; + } + block_no = block_offset + SB->blocks_per_group * i; + group = i; + break; + } + } + + if (!block_no) { + debug_print(CRITICAL, "No available blocks, disk is out of space!"); + free(bg_buffer); + return 0; + } + + debug_print(WARNING, "allocating block #%d (group %d)", block_no, group); + + BLOCKBYTE(block_offset) |= SETBIT(block_offset); + write_block(this, BGD[group].block_bitmap, (uint8_t *)bg_buffer); + + BGD[group].free_blocks_count--; + for (int i = 0; i < this->bgd_block_span; ++i) { + write_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i)); + } + + SB->free_blocks_count--; + rewrite_superblock(this); + + memset(bg_buffer, 0x00, this->block_size); + write_block(this, block_no, bg_buffer); + + free(bg_buffer); + + return block_no; + +} + + +/** + * ext2->allocate_inode_block Allocate a block in an inode. + * + * @param inode Inode to operate on + * @param inode_no Number of the inode (this is not part of the struct) + * @param block Block within inode to allocate + * @returns Error code or E_SUCCESS + */ +static int allocate_inode_block(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int inode_no, unsigned int block) { + debug_print(NOTICE, "Allocating block #%d for inode #%d", block, inode_no); + unsigned int block_no = allocate_block(this); + + if (!block_no) return E_NOSPACE; + + set_block_number(this, inode, inode_no, block, block_no); + + unsigned int t = (block + 1) * (this->block_size / 512); + if (inode->blocks < t) { + debug_print(NOTICE, "Setting inode->blocks to %d = (%d fs blocks)", t, t / (this->block_size / 512)); + inode->blocks = t; + } + write_inode(this, inode, inode_no); + + return E_SUCCESS; +} + +/** + * ext2->inode_read_block + * + * @param inode + * @param no + * @param block + * @parma buf + * @returns Real block number for reference. + */ +static unsigned int inode_read_block(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int block, uint8_t * buf) { + + if (block >= inode->blocks / (this->block_size / 512)) { + memset(buf, 0x00, this->block_size); + debug_print(WARNING, "Tried to read an invalid block. Asked for %d (0-indexed), but inode only has %d!", block, inode->blocks / (this->block_size / 512)); + return 0; + } + + unsigned int real_block = get_block_number(this, inode, block); + read_block(this, real_block, buf); + + return real_block; +} + +/** + * ext2->inode_write_block + */ +static unsigned int inode_write_block(ext2_fs_t * this, ext2_inodetable_t * inode, unsigned int inode_no, unsigned int block, uint8_t * buf) { + if (block >= inode->blocks / (this->block_size / 512)) { + debug_print(WARNING, "Attempting to write beyond the existing allocated blocks for this inode."); + debug_print(WARNING, "Inode %d, Block %d", inode_no, block); + } + + debug_print(WARNING, "clearing and allocating up to required blocks (block=%d, %d)", block, inode->blocks); + char * empty = NULL; + while (block >= inode->blocks / (this->block_size / 512)) { + allocate_inode_block(this, inode, inode_no, inode->blocks / (this->block_size / 512)); + refresh_inode(this, inode, inode_no); + } + if (empty) free(empty); + debug_print(WARNING, "... done"); + + unsigned int real_block = get_block_number(this, inode, block); + debug_print(WARNING, "Writing virtual block %d for inode %d maps to real block %d", block, inode_no, real_block); + + write_block(this, real_block, buf); + return real_block; +} + +/** + * ext2->create_entry + * + * @returns Error code or E_SUCCESS + */ +static int create_entry(fs_node_t * parent, char * name, uint32_t inode) { + ext2_fs_t * this = (ext2_fs_t *)parent->device; + + ext2_inodetable_t * pinode = read_inode(this,parent->inode); + if (((pinode->mode & EXT2_S_IFDIR) == 0) || (name == NULL)) { + debug_print(WARNING, "Attempted to allocate an inode in a parent that was not a directory."); + return E_BADPARENT; + } + + debug_print(WARNING, "Creating a directory entry for %s pointing to inode %d.", name, inode); + + /* okay, how big is it... */ + + debug_print(WARNING, "We need to append %d bytes to the direcotry.", sizeof(ext2_dir_t) + strlen(name)); + + unsigned int rec_len = sizeof(ext2_dir_t) + strlen(name); + rec_len += (rec_len % 4) ? (4 - (rec_len % 4)) : 0; + + debug_print(WARNING, "Our directory entry looks like this:"); + debug_print(WARNING, " inode = %d", inode); + debug_print(WARNING, " rec_len = %d", rec_len); + debug_print(WARNING, " name_len = %d", strlen(name)); + debug_print(WARNING, " file_type = %d", 0); + debug_print(WARNING, " name = %s", name); + + debug_print(WARNING, "The inode size is marked as: %d", pinode->size); + debug_print(WARNING, "Block size is %d", this->block_size); + + uint8_t * block = malloc(this->block_size); + uint8_t block_nr = 0; + uint32_t dir_offset = 0; + uint32_t total_offset = 0; + int modify_or_replace = 0; + ext2_dir_t *previous; + + inode_read_block(this, pinode, block_nr, block); + while (total_offset < pinode->size) { + if (dir_offset >= this->block_size) { + block_nr++; + dir_offset -= this->block_size; + inode_read_block(this, pinode, block_nr, block); + } + ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); + + unsigned int sreclen = d_ent->name_len + sizeof(ext2_dir_t); + sreclen += (sreclen % 4) ? (4 - (sreclen % 4)) : 0; + + { + char f[d_ent->name_len+1]; + memcpy(f, d_ent->name, d_ent->name_len); + f[d_ent->name_len] = 0; + debug_print(WARNING, " * file: %s", f); + } + debug_print(WARNING, " rec_len: %d", d_ent->rec_len); + debug_print(WARNING, " type: %d", d_ent->file_type); + debug_print(WARNING, " namel: %d", d_ent->name_len); + debug_print(WARNING, " inode: %d", d_ent->inode); + + if (d_ent->rec_len != sreclen && total_offset + d_ent->rec_len == pinode->size) { + debug_print(WARNING, " - should be %d, but instead points to end of block", sreclen); + debug_print(WARNING, " - we've hit the end, should change this pointer"); + + dir_offset += sreclen; + total_offset += sreclen; + + modify_or_replace = 1; /* Modify */ + previous = d_ent; + + break; + } + + if (d_ent->inode == 0) { + modify_or_replace = 2; /* Replace */ + } + + dir_offset += d_ent->rec_len; + total_offset += d_ent->rec_len; + } + + if (!modify_or_replace) { + debug_print(WARNING, "That's odd, this shouldn't have happened, we made it all the way here without hitting our two end conditions?"); + } + + if (modify_or_replace == 1) { + debug_print(WARNING, "The last node in the list is a real node, we need to modify it."); + + if (dir_offset + rec_len >= this->block_size) { + debug_print(WARNING, "Need to allocate more space, bail!"); + free(block); + return E_NOSPACE; + } else { + unsigned int sreclen = previous->name_len + sizeof(ext2_dir_t); + sreclen += (sreclen % 4) ? (4 - (sreclen % 4)) : 0; + previous->rec_len = sreclen; + debug_print(WARNING, "Set previous node rec_len to %d", sreclen); + } + + } else if (modify_or_replace == 2) { + debug_print(WARNING, "The last node in the list is a fake node, we'll replace it."); + } + + debug_print(WARNING, " total_offset = 0x%x", total_offset); + debug_print(WARNING, " dir_offset = 0x%x", dir_offset); + ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); + + d_ent->inode = inode; + d_ent->rec_len = this->block_size - dir_offset; + d_ent->name_len = strlen(name); + d_ent->file_type = 0; /* This is unused */ + memcpy(d_ent->name, name, strlen(name)); + + inode_write_block(this, pinode, parent->inode, block_nr, block); + + free(block); + free(pinode); + + + return E_NOSPACE; +} + +static unsigned int allocate_inode(ext2_fs_t * this) { + uint32_t node_no = 0; + uint32_t node_offset = 0; + uint32_t group = 0; + uint8_t * bg_buffer = malloc(this->block_size); + + for (unsigned int i = 0; i < BGDS; ++i) { + if (BGD[i].free_inodes_count > 0) { + debug_print(NOTICE, "Group %d has %d free inodes.", i, BGD[i].free_inodes_count); + read_block(this, BGD[i].inode_bitmap, (uint8_t *)bg_buffer); + while (BLOCKBIT(node_offset)) { + node_offset++; + } + node_no = node_offset + i * this->inodes_per_group + 1; + group = i; + break; + } + } + if (!node_no) { + debug_print(ERROR, "Ran out of inodes!"); + return 0; + } + + BLOCKBYTE(node_offset) |= SETBIT(node_offset); + + write_block(this, BGD[group].inode_bitmap, (uint8_t *)bg_buffer); + free(bg_buffer); + + BGD[group].free_inodes_count--; + for (int i = 0; i < this->bgd_block_span; ++i) { + write_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i)); + } + + SB->free_inodes_count--; + rewrite_superblock(this); + + return node_no; +} + +static void mkdir_ext2(fs_node_t * parent, char * name, uint16_t permission) { + if (!name) return; + + ext2_fs_t * this = parent->device; + + /* first off, check if it exists */ + fs_node_t * check = finddir_ext2(parent, name); + if (check) { + debug_print(WARNING, "A file by this name already exists: %s", name); + free(check); + return; /* this should probably have a return value... */ + } + + /* Allocate an inode for it */ + unsigned int inode_no = allocate_inode(this); + ext2_inodetable_t * inode = read_inode(this,inode_no); + + /* Set the access and creation times to now */ + inode->atime = now(); + inode->ctime = inode->atime; + inode->mtime = inode->atime; + inode->dtime = 0; /* This inode was never deleted */ + + /* Empty the file */ + memset(inode->block, 0x00, sizeof(inode->block)); + inode->blocks = 0; + inode->size = 0; /* empty */ + + /* Assign it to root */ + inode->uid = current_process->user; /* user */ + inode->gid = current_process->user; + + /* misc */ + inode->faddr = 0; + inode->links_count = 2; /* There's the parent's pointer to us, and our pointer to us. */ + inode->flags = 0; + inode->osd1 = 0; + inode->generation = 0; + inode->file_acl = 0; + inode->dir_acl = 0; + + /* File mode */ + inode->mode = EXT2_S_IFDIR; + inode->mode |= 0xFFF & permission; + + /* Write the osd blocks to 0 */ + memset(inode->osd2, 0x00, sizeof(inode->osd2)); + + /* Write out inode changes */ + write_inode(this, inode, inode_no); + + /* Now append the entry to the parent */ + create_entry(parent, name, inode_no); + + inode->size = this->block_size; + write_inode(this, inode, inode_no); + + uint8_t * tmp = malloc(this->block_size); + ext2_dir_t * t = calloc(12,1); + t->inode = inode_no; + t->rec_len = 12; + t->name_len = 1; + t->name[0] = '.'; + memcpy(&tmp[0], t, 12); + t->inode = parent->inode; + t->name_len = 2; + t->name[1] = '.'; + t->rec_len = this->block_size - 12; + memcpy(&tmp[12], t, 12); + free(t); + + inode_write_block(this, inode, inode_no, 0, tmp); + + free(inode); + free(tmp); + + /* Update parent link count */ + ext2_inodetable_t * pinode = read_inode(this, parent->inode); + pinode->links_count++; + write_inode(this, pinode, parent->inode); + free(pinode); + + /* Update directory count in block group descriptor */ + uint32_t group = inode_no / this->inodes_per_group; + BGD[group].used_dirs_count++; + for (int i = 0; i < this->bgd_block_span; ++i) { + write_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i)); + } + + ext2_sync(this); + +} + +static void create_ext2(fs_node_t * parent, char * name, uint16_t permission) { + if (!name) return; + + ext2_fs_t * this = parent->device; + + /* first off, check if it exists */ + fs_node_t * check = finddir_ext2(parent, name); + if (check) { + debug_print(WARNING, "A file by this name already exists: %s", name); + free(check); + return; /* this should probably have a return value... */ + } + + /* Allocate an inode for it */ + unsigned int inode_no = allocate_inode(this); + ext2_inodetable_t * inode = read_inode(this,inode_no); + + /* Set the access and creation times to now */ + inode->atime = now(); + inode->ctime = inode->atime; + inode->mtime = inode->atime; + inode->dtime = 0; /* This inode was never deleted */ + + /* Empty the file */ + memset(inode->block, 0x00, sizeof(inode->block)); + inode->blocks = 0; + inode->size = 0; /* empty */ + + /* Assign it to root */ + inode->uid = current_process->user; /* user */ + inode->gid = current_process->user; + + /* misc */ + inode->faddr = 0; + inode->links_count = 1; /* The one we're about to create. */ + inode->flags = 0; + inode->osd1 = 0; + inode->generation = 0; + inode->file_acl = 0; + inode->dir_acl = 0; + + /* File mode */ + /* TODO: Use the mask from `permission` */ + inode->mode = EXT2_S_IFREG; + inode->mode |= 0xFFF & permission; + + /* Write the osd blocks to 0 */ + memset(inode->osd2, 0x00, sizeof(inode->osd2)); + + /* Write out inode changes */ + write_inode(this, inode, inode_no); + + /* Now append the entry to the parent */ + create_entry(parent, name, inode_no); + + free(inode); + + ext2_sync(this); + +} + +static int chmod_ext2(fs_node_t * node, int mode) { + ext2_fs_t * this = node->device; + + ext2_inodetable_t * inode = read_inode(this,node->inode); + + inode->mode = (inode->mode & 0xFFFFF000) | mode; + + write_inode(this, inode, node->inode); + + ext2_sync(this); + + return 0; +} + +/** + * direntry_ext2 + */ +static ext2_dir_t * direntry_ext2(ext2_fs_t * this, ext2_inodetable_t * inode, uint32_t no, uint32_t index) { + uint8_t *block = malloc(this->block_size); + uint8_t block_nr = 0; + inode_read_block(this, inode, block_nr, block); + uint32_t dir_offset = 0; + uint32_t total_offset = 0; + uint32_t dir_index = 0; + + while (total_offset < inode->size && dir_index <= index) { + ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); + + if (d_ent->inode != 0 && dir_index == index) { + ext2_dir_t *out = malloc(d_ent->rec_len); + memcpy(out, d_ent, d_ent->rec_len); + free(block); + return out; + } + + dir_offset += d_ent->rec_len; + total_offset += d_ent->rec_len; + + if (d_ent->inode) { + dir_index++; + } + + if (dir_offset >= this->block_size) { + block_nr++; + dir_offset -= this->block_size; + inode_read_block(this, inode, block_nr, block); + } + } + + free(block); + return NULL; +} + +/** + * finddir_ext2 + */ +static fs_node_t * finddir_ext2(fs_node_t *node, char *name) { + + ext2_fs_t * this = (ext2_fs_t *)node->device; + + ext2_inodetable_t *inode = read_inode(this,node->inode); + assert(inode->mode & EXT2_S_IFDIR); + uint8_t * block = malloc(this->block_size); + ext2_dir_t *direntry = NULL; + uint8_t block_nr = 0; + inode_read_block(this, inode, block_nr, block); + uint32_t dir_offset = 0; + uint32_t total_offset = 0; + + while (total_offset < inode->size) { + if (dir_offset >= this->block_size) { + block_nr++; + dir_offset -= this->block_size; + inode_read_block(this, inode, block_nr, block); + } + ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); + + if (d_ent->inode == 0 || strlen(name) != d_ent->name_len) { + dir_offset += d_ent->rec_len; + total_offset += d_ent->rec_len; + + continue; + } + + char *dname = malloc(sizeof(char) * (d_ent->name_len + 1)); + memcpy(dname, &(d_ent->name), d_ent->name_len); + dname[d_ent->name_len] = '\0'; + if (!strcmp(dname, name)) { + free(dname); + direntry = malloc(d_ent->rec_len); + memcpy(direntry, d_ent, d_ent->rec_len); + break; + } + free(dname); + + dir_offset += d_ent->rec_len; + total_offset += d_ent->rec_len; + } + free(inode); + if (!direntry) { + free(block); + return NULL; + } + fs_node_t *outnode = malloc(sizeof(fs_node_t)); + memset(outnode, 0, sizeof(fs_node_t)); + + inode = read_inode(this, direntry->inode); + + if (!node_from_file(this, inode, direntry, outnode)) { + debug_print(CRITICAL, "Oh dear. Couldn't allocate the outnode?"); + } + + free(direntry); + free(inode); + free(block); + return outnode; +} + +static void unlink_ext2(fs_node_t * node, char * name) { + /* XXX this is a very bad implementation */ + ext2_fs_t * this = (ext2_fs_t *)node->device; + + ext2_inodetable_t *inode = read_inode(this,node->inode); + assert(inode->mode & EXT2_S_IFDIR); + uint8_t * block = malloc(this->block_size); + ext2_dir_t *direntry = NULL; + uint8_t block_nr = 0; + inode_read_block(this, inode, block_nr, block); + uint32_t dir_offset = 0; + uint32_t total_offset = 0; + + while (total_offset < inode->size) { + if (dir_offset >= this->block_size) { + block_nr++; + dir_offset -= this->block_size; + inode_read_block(this, inode, block_nr, block); + } + ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); + + if (d_ent->inode == 0 || strlen(name) != d_ent->name_len) { + dir_offset += d_ent->rec_len; + total_offset += d_ent->rec_len; + + continue; + } + + char *dname = malloc(sizeof(char) * (d_ent->name_len + 1)); + memcpy(dname, &(d_ent->name), d_ent->name_len); + dname[d_ent->name_len] = '\0'; + if (!strcmp(dname, name)) { + free(dname); + direntry = d_ent; + break; + } + free(dname); + + dir_offset += d_ent->rec_len; + total_offset += d_ent->rec_len; + } + free(inode); + if (!direntry) { + free(block); + return; + } + + direntry->inode = 0; + + inode_write_block(this, inode, node->inode, block_nr, block); + free(block); + + ext2_sync(this); +} + + +static void refresh_inode(ext2_fs_t * this, ext2_inodetable_t * inodet, uint32_t inode) { + uint32_t group = inode / this->inodes_per_group; + if (group > BGDS) { + return; + } + uint32_t inode_table_block = BGD[group].inode_table; + inode -= group * this->inodes_per_group; // adjust index within group + uint32_t block_offset = ((inode - 1) * this->inode_size) / this->block_size; + uint32_t offset_in_block = (inode - 1) - block_offset * (this->block_size / this->inode_size); + + uint8_t * buf = malloc(this->block_size); + + read_block(this, inode_table_block + block_offset, buf); + + ext2_inodetable_t *inodes = (ext2_inodetable_t *)buf; + + memcpy(inodet, (uint8_t *)((uint32_t)inodes + offset_in_block * this->inode_size), this->inode_size); + + free(buf); +} + +/** + * read_inode + */ +static ext2_inodetable_t * read_inode(ext2_fs_t * this, uint32_t inode) { + ext2_inodetable_t *inodet = malloc(this->inode_size); + refresh_inode(this, inodet, inode); + return inodet; +} + +static uint32_t read_ext2(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + ext2_fs_t * this = (ext2_fs_t *)node->device; + ext2_inodetable_t * inode = read_inode(this, node->inode); + uint32_t end; + if (inode->size == 0) return 0; + if (offset + size > inode->size) { + end = inode->size; + } else { + end = offset + size; + } + uint32_t start_block = offset / this->block_size; + uint32_t end_block = end / this->block_size; + uint32_t end_size = end - end_block * this->block_size; + uint32_t size_to_read = end - offset; + + uint8_t * buf = malloc(this->block_size); + if (start_block == end_block) { + inode_read_block(this, inode, start_block, buf); + memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % this->block_size)), size_to_read); + } else { + uint32_t block_offset; + uint32_t blocks_read = 0; + for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { + if (block_offset == start_block) { + inode_read_block(this, inode, block_offset, buf); + memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % this->block_size)), this->block_size - (offset % this->block_size)); + } else { + inode_read_block(this, inode, block_offset, buf); + memcpy(buffer + this->block_size * blocks_read - (offset % this->block_size), buf, this->block_size); + } + } + if (end_size) { + inode_read_block(this, inode, end_block, buf); + memcpy(buffer + this->block_size * blocks_read - (offset % this->block_size), buf, end_size); + } + } + free(inode); + free(buf); + return size_to_read; +} + +static uint32_t write_inode_buffer(ext2_fs_t * this, ext2_inodetable_t * inode, uint32_t inode_number, uint32_t offset, uint32_t size, uint8_t *buffer) { + uint32_t end = offset + size; + if (end > inode->size) { + inode->size = end; + write_inode(this, inode, inode_number); + } + + uint32_t start_block = offset / this->block_size; + uint32_t end_block = end / this->block_size; + uint32_t end_size = end - end_block * this->block_size; + uint32_t size_to_read = end - offset; + uint8_t * buf = malloc(this->block_size); + if (start_block == end_block) { + inode_read_block(this, inode, start_block, buf); + memcpy((uint8_t *)(((uint32_t)buf) + (offset % this->block_size)), buffer, size_to_read); + inode_write_block(this, inode, inode_number, start_block, buf); + } else { + uint32_t block_offset; + uint32_t blocks_read = 0; + for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { + if (block_offset == start_block) { + int b = inode_read_block(this, inode, block_offset, buf); + memcpy((uint8_t *)(((uint32_t)buf) + (offset % this->block_size)), buffer, this->block_size - (offset % this->block_size)); + inode_write_block(this, inode, inode_number, block_offset, buf); + if (!b) { + refresh_inode(this, inode, inode_number); + } + } else { + int b = inode_read_block(this, inode, block_offset, buf); + memcpy(buf, buffer + this->block_size * blocks_read - (offset % this->block_size), this->block_size); + inode_write_block(this, inode, inode_number, block_offset, buf); + if (!b) { + refresh_inode(this, inode, inode_number); + } + } + } + if (end_size) { + inode_read_block(this, inode, end_block, buf); + memcpy(buf, buffer + this->block_size * blocks_read - (offset % this->block_size), end_size); + inode_write_block(this, inode, inode_number, end_block, buf); + } + } + free(buf); + return size_to_read; +} + +static uint32_t write_ext2(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + ext2_fs_t * this = (ext2_fs_t *)node->device; + ext2_inodetable_t * inode = read_inode(this, node->inode); + + uint32_t rv = write_inode_buffer(this, inode, node->inode, offset, size, buffer); + free(inode); + return rv; +} + +static void open_ext2(fs_node_t *node, unsigned int flags) { + ext2_fs_t * this = node->device; + + if (flags & O_TRUNC) { + /* Uh, herp */ + ext2_inodetable_t * inode = read_inode(this,node->inode); + inode->size = 0; + write_inode(this, inode, node->inode); + } +} + +static void close_ext2(fs_node_t *node) { + /* Nothing to do here */ +} + + +/** + * readdir_ext2 + */ +static struct dirent * readdir_ext2(fs_node_t *node, uint32_t index) { + + ext2_fs_t * this = (ext2_fs_t *)node->device; + + ext2_inodetable_t *inode = read_inode(this, node->inode); + assert(inode->mode & EXT2_S_IFDIR); + ext2_dir_t *direntry = direntry_ext2(this, inode, node->inode, index); + if (!direntry) { + free(inode); + return NULL; + } + struct dirent *dirent = malloc(sizeof(struct dirent)); + memcpy(&dirent->name, &direntry->name, direntry->name_len); + dirent->name[direntry->name_len] = '\0'; + dirent->ino = direntry->inode; + free(direntry); + free(inode); + return dirent; +} + +static void symlink_ext2(fs_node_t * parent, char * target, char * name) { + if (!name) return; + + ext2_fs_t * this = parent->device; + + /* first off, check if it exists */ + fs_node_t * check = finddir_ext2(parent, name); + if (check) { + debug_print(WARNING, "A file by this name already exists: %s", name); + free(check); + return; /* this should probably have a return value... */ + } + + /* Allocate an inode for it */ + unsigned int inode_no = allocate_inode(this); + ext2_inodetable_t * inode = read_inode(this,inode_no); + + /* Set the access and creation times to now */ + inode->atime = now(); + inode->ctime = inode->atime; + inode->mtime = inode->atime; + inode->dtime = 0; /* This inode was never deleted */ + + /* Empty the file */ + memset(inode->block, 0x00, sizeof(inode->block)); + inode->blocks = 0; + inode->size = 0; /* empty */ + + /* Assign it to current user */ + inode->uid = current_process->user; + inode->gid = current_process->user; + + /* misc */ + inode->faddr = 0; + inode->links_count = 1; /* The one we're about to create. */ + inode->flags = 0; + inode->osd1 = 0; + inode->generation = 0; + inode->file_acl = 0; + inode->dir_acl = 0; + + inode->mode = EXT2_S_IFLNK; + + /* I *think* this is what you're supposed to do with symlinks */ + inode->mode |= 0777; + + /* Write the osd blocks to 0 */ + memset(inode->osd2, 0x00, sizeof(inode->osd2)); + + size_t target_len = strlen(target); + int embedded = target_len <= 60; // sizeof(_symlink(inode)); + if (embedded) { + memcpy(_symlink(inode), target, target_len); + inode->size = target_len; + } + + /* Write out inode changes */ + write_inode(this, inode, inode_no); + + /* Now append the entry to the parent */ + create_entry(parent, name, inode_no); + + + /* If we didn't embed it in the inode just use write_inode_buffer to finish the job */ + if (!embedded) { + write_inode_buffer(parent->device, inode, inode_no, 0, target_len, (uint8_t *)target); + } + free(inode); + + ext2_sync(this); +} + +static int readlink_ext2(fs_node_t * node, char * buf, size_t size) { + ext2_fs_t * this = (ext2_fs_t *)node->device; + ext2_inodetable_t * inode = read_inode(this, node->inode); + size_t read_size = inode->size < size ? inode->size : size; + if (inode->size > 60) { //sizeof(_symlink(inode))) { + read_ext2(node, 0, read_size, (uint8_t *)buf); + } else { + memcpy(buf, _symlink(inode), read_size); + } + + /* Believe it or not, we actually aren't supposed to include the nul in the length. */ + if (read_size < size) { + buf[read_size] = '\0'; + } + + free(inode); + return read_size; +} + + + +static uint32_t node_from_file(ext2_fs_t * this, ext2_inodetable_t *inode, ext2_dir_t *direntry, fs_node_t *fnode) { + if (!fnode) { + /* You didn't give me a node to write into, go **** yourself */ + return 0; + } + /* Information from the direntry */ + fnode->device = (void *)this; + fnode->inode = direntry->inode; + memcpy(&fnode->name, &direntry->name, direntry->name_len); + fnode->name[direntry->name_len] = '\0'; + /* Information from the inode */ + fnode->uid = inode->uid; + fnode->gid = inode->gid; + fnode->length = inode->size; + fnode->mask = inode->mode & 0xFFF; + fnode->nlink = inode->links_count; + /* File Flags */ + fnode->flags = 0; + if ((inode->mode & EXT2_S_IFREG) == EXT2_S_IFREG) { + fnode->flags |= FS_FILE; + fnode->read = read_ext2; + fnode->write = write_ext2; + fnode->create = NULL; + fnode->mkdir = NULL; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->symlink = NULL; + fnode->readlink = NULL; + } + if ((inode->mode & EXT2_S_IFDIR) == EXT2_S_IFDIR) { + fnode->flags |= FS_DIRECTORY; + fnode->create = create_ext2; + fnode->mkdir = mkdir_ext2; + fnode->readdir = readdir_ext2; + fnode->finddir = finddir_ext2; + fnode->unlink = unlink_ext2; + fnode->write = NULL; + fnode->symlink = symlink_ext2; + fnode->readlink = NULL; + } + if ((inode->mode & EXT2_S_IFBLK) == EXT2_S_IFBLK) { + fnode->flags |= FS_BLOCKDEVICE; + } + if ((inode->mode & EXT2_S_IFCHR) == EXT2_S_IFCHR) { + fnode->flags |= FS_CHARDEVICE; + } + if ((inode->mode & EXT2_S_IFIFO) == EXT2_S_IFIFO) { + fnode->flags |= FS_PIPE; + } + if ((inode->mode & EXT2_S_IFLNK) == EXT2_S_IFLNK) { + fnode->flags |= FS_SYMLINK; + fnode->read = NULL; + fnode->write = NULL; + fnode->create = NULL; + fnode->mkdir = NULL; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->readlink = readlink_ext2; + } + + fnode->atime = inode->atime; + fnode->mtime = inode->mtime; + fnode->ctime = inode->ctime; + debug_print(INFO, "file a/m/c times are %d/%d/%d", fnode->atime, fnode->mtime, fnode->ctime); + + fnode->chmod = chmod_ext2; + fnode->open = open_ext2; + fnode->close = close_ext2; + fnode->ioctl = NULL; + return 1; +} + +static uint32_t ext2_root(ext2_fs_t * this, ext2_inodetable_t *inode, fs_node_t *fnode) { + if (!fnode) { + return 0; + } + /* Information for root dir */ + fnode->device = (void *)this; + fnode->inode = 2; + fnode->name[0] = '/'; + fnode->name[1] = '\0'; + /* Information from the inode */ + fnode->uid = inode->uid; + fnode->gid = inode->gid; + fnode->length = inode->size; + fnode->mask = inode->mode & 0xFFF; + fnode->nlink = inode->links_count; + /* File Flags */ + fnode->flags = 0; + if ((inode->mode & EXT2_S_IFREG) == EXT2_S_IFREG) { + debug_print(CRITICAL, "Root appears to be a regular file."); + debug_print(CRITICAL, "This is probably very, very wrong."); + return 0; + } + if ((inode->mode & EXT2_S_IFDIR) == EXT2_S_IFDIR) { + } else { + debug_print(CRITICAL, "Root doesn't appear to be a directory."); + debug_print(CRITICAL, "This is probably very, very wrong."); + + debug_print(ERROR, "Other useful information:"); + debug_print(ERROR, "%d", inode->uid); + debug_print(ERROR, "%d", inode->gid); + debug_print(ERROR, "%d", inode->size); + debug_print(ERROR, "%d", inode->mode); + debug_print(ERROR, "%d", inode->links_count); + + return 0; + } + if ((inode->mode & EXT2_S_IFBLK) == EXT2_S_IFBLK) { + fnode->flags |= FS_BLOCKDEVICE; + } + if ((inode->mode & EXT2_S_IFCHR) == EXT2_S_IFCHR) { + fnode->flags |= FS_CHARDEVICE; + } + if ((inode->mode & EXT2_S_IFIFO) == EXT2_S_IFIFO) { + fnode->flags |= FS_PIPE; + } + if ((inode->mode & EXT2_S_IFLNK) == EXT2_S_IFLNK) { + fnode->flags |= FS_SYMLINK; + } + + fnode->atime = inode->atime; + fnode->mtime = inode->mtime; + fnode->ctime = inode->ctime; + + fnode->flags |= FS_DIRECTORY; + fnode->read = NULL; + fnode->write = NULL; + fnode->chmod = chmod_ext2; + fnode->open = open_ext2; + fnode->close = close_ext2; + fnode->readdir = readdir_ext2; + fnode->finddir = finddir_ext2; + fnode->ioctl = NULL; + fnode->create = create_ext2; + fnode->mkdir = mkdir_ext2; + fnode->unlink = unlink_ext2; + return 1; +} + +static fs_node_t * mount_ext2(fs_node_t * block_device, int flags) { + + debug_print(NOTICE, "Mounting ext2 file system..."); + ext2_fs_t * this = malloc(sizeof(ext2_fs_t)); + + memset(this, 0x00, sizeof(ext2_fs_t)); + + this->flags = flags; + + this->block_device = block_device; + this->block_size = 1024; + vfs_lock(this->block_device); + + SB = malloc(this->block_size); + + debug_print(INFO, "Reading superblock..."); + read_block(this, 1, (uint8_t *)SB); + if (SB->magic != EXT2_SUPER_MAGIC) { + debug_print(ERROR, "... not an EXT2 filesystem? (magic didn't match, got 0x%x)", SB->magic); + return NULL; + } + this->inode_size = SB->inode_size; + if (SB->inode_size == 0) { + this->inode_size = 128; + } + this->block_size = 1024 << SB->log_block_size; + this->cache_entries = 10240; + if (this->block_size > 2048) { + this->cache_entries /= 4; + } + debug_print(INFO, "bs=%d, cache entries=%d", this->block_size, this->cache_entries); + this->pointers_per_block = this->block_size / 4; + debug_print(INFO, "Log block size = %d -> %d", SB->log_block_size, this->block_size); + BGDS = SB->blocks_count / SB->blocks_per_group; + if (SB->blocks_per_group * BGDS < SB->blocks_count) { + BGDS += 1; + } + this->inodes_per_group = SB->inodes_count / BGDS; + + if (!(this->flags & EXT2_FLAG_NOCACHE)) { + debug_print(INFO, "Allocating cache..."); + DC = malloc(sizeof(ext2_disk_cache_entry_t) * this->cache_entries); + this->cache_data = calloc(this->block_size, this->cache_entries); + for (uint32_t i = 0; i < this->cache_entries; ++i) { + DC[i].block_no = 0; + DC[i].dirty = 0; + DC[i].last_use = 0; + DC[i].block = this->cache_data + i * this->block_size; + if (i % 128 == 0) { + debug_print(INFO, "Allocated cache block #%d", i+1); + } + } + debug_print(INFO, "Allocated cache."); + } else { + DC = NULL; + debug_print(NOTICE, "ext2 cache is disabled (nocache)"); + } + + // load the block group descriptors + this->bgd_block_span = sizeof(ext2_bgdescriptor_t) * BGDS / this->block_size + 1; + BGD = malloc(this->block_size * this->bgd_block_span); + + debug_print(INFO, "bgd_block_span = %d", this->bgd_block_span); + + this->bgd_offset = 2; + + if (this->block_size > 1024) { + this->bgd_offset = 1; + } + + for (int i = 0; i < this->bgd_block_span; ++i) { + read_block(this, this->bgd_offset + i, (uint8_t *)((uint32_t)BGD + this->block_size * i)); + } + +#ifdef DEBUG_BLOCK_DESCRIPTORS + char * bg_buffer = malloc(this->block_size * sizeof(char)); + for (uint32_t i = 0; i < BGDS; ++i) { + debug_print(INFO, "Block Group Descriptor #%d @ %d", i, this->bgd_offset + i * SB->blocks_per_group); + debug_print(INFO, "\tBlock Bitmap @ %d", BGD[i].block_bitmap); { + debug_print(INFO, "\t\tExamining block bitmap at %d", BGD[i].block_bitmap); + read_block(this, BGD[i].block_bitmap, (uint8_t *)bg_buffer); + uint32_t j = 0; + while (BLOCKBIT(j)) { + ++j; + } + debug_print(INFO, "\t\tFirst free block in group is %d", j + BGD[i].block_bitmap - 2); + } + debug_print(INFO, "\tInode Bitmap @ %d", BGD[i].inode_bitmap); { + debug_print(INFO, "\t\tExamining inode bitmap at %d", BGD[i].inode_bitmap); + read_block(this, BGD[i].inode_bitmap, (uint8_t *)bg_buffer); + uint32_t j = 0; + while (BLOCKBIT(j)) { + ++j; + } + debug_print(INFO, "\t\tFirst free inode in group is %d", j + this->inodes_per_group * i + 1); + } + debug_print(INFO, "\tInode Table @ %d", BGD[i].inode_table); + debug_print(INFO, "\tFree Blocks = %d", BGD[i].free_blocks_count); + debug_print(INFO, "\tFree Inodes = %d", BGD[i].free_inodes_count); + } + free(bg_buffer); +#endif + + ext2_inodetable_t *root_inode = read_inode(this, 2); + RN = (fs_node_t *)malloc(sizeof(fs_node_t)); + if (!ext2_root(this, root_inode, RN)) { + return NULL; + } + debug_print(NOTICE, "Mounted EXT2 disk, root VFS node is at 0x%x", RN); + return RN; +} + +fs_node_t * ext2_fs_mount(char * device, char * mount_path) { + + char * arg = strdup(device); + char * argv[10]; + int argc = tokenize(arg, ",", argv); + + fs_node_t * dev = kopen(argv[0], 0); + if (!dev) { + debug_print(ERROR, "failed to open %s", device); + return NULL; + } + + int flags = 0; + + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i],"nocache")) { + flags |= EXT2_FLAG_NOCACHE; + } else { + debug_print(WARNING, "Unrecognized option to ext2 driver: %s", argv[i]); + } + } + + fs_node_t * fs = mount_ext2(dev, flags); + + free(arg); + return fs; +} + +int ext2_initialize(void) { + + vfs_register("ext2", ext2_fs_mount); + + return 0; +} + +int ext2_finalize(void) { + + return 0; +} + +MODULE_DEF(ext2, ext2_initialize, ext2_finalize); + diff --git a/modules/hda.c b/modules/hda.c new file mode 100644 index 00000000..eb79699c --- /dev/null +++ b/modules/hda.c @@ -0,0 +1,51 @@ +/* + * Experimental Intel High-Definition Audio "driver" + */ + +#include +#include +#include +#include + +struct hda_device { + uint32_t pci_device; +}; + +static struct hda_device _device; + +static void find_hda(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + + struct hda_device * hda = extra; + + if ((vendorid == 0x8086) && (deviceid == 0x2668)) { + hda->pci_device = device; + } + +} + +DEFINE_SHELL_FUNCTION(hda_test, "[debug] Intel HDA experiments") { + + if (!_device.pci_device) { + fprintf(tty, "No HDA device found.\n"); + return 1; + } + fprintf(tty, "HDA audio device is at 0x%x.\n", _device.pci_device); + + return 0; +} + +static int init(void) { + BIND_SHELL_FUNCTION(hda_test); + pci_scan(&find_hda, -1, &_device); + if (!_device.pci_device) { + return 1; + } + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(hda, init, fini); +MODULE_DEPENDS(debugshell); diff --git a/modules/iso9660.c b/modules/iso9660.c new file mode 100644 index 00000000..2885f875 --- /dev/null +++ b/modules/iso9660.c @@ -0,0 +1,508 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016 Kevin Lange + * + * ISO 9660 filesystem driver (for CDs) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ISO_SECTOR_SIZE 2048 + +#define FLAG_HIDDEN 0x01 +#define FLAG_DIRECTORY 0x02 +#define FLAG_ASSOCIATED 0x04 +#define FLAG_EXTENDED 0x08 +#define FLAG_PERMISSIONS 0x10 +#define FLAG_CONTINUES 0x80 + +typedef struct { + fs_node_t * block_device; + uint32_t block_size; + hashmap_t * cache; + list_t * lru; +} iso_9660_fs_t; + +typedef struct { + char year[4]; + char month[2]; + char day[2]; + char hour[2]; + char minute[2]; + char second[2]; + char hundredths[2]; + int8_t timezone; +} __attribute__((packed)) iso_9660_datetime_t; + +typedef struct { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + int8_t timezone; +} __attribute__((packed)) iso_9660_rec_date_t; + +typedef struct { + uint8_t length; + uint8_t ext_length; + + uint32_t extent_start_LSB; + uint32_t extent_start_MSB; + + uint32_t extent_length_LSB; + uint32_t extent_length_MSB; + + iso_9660_rec_date_t record_date; + + uint8_t flags; + uint8_t interleave_units; + uint8_t interleave_gap; + + uint16_t volume_seq_LSB; + uint16_t volume_seq_MSB; + + uint8_t name_len; + char name[]; +} __attribute__((packed)) iso_9660_directory_entry_t; + +typedef struct { + uint8_t type; /* 0x01 */ + char id[5]; /* CD001 */ + + uint8_t version; + uint8_t _unused0; + + char system_id[32]; + char volume_id[32]; + + uint8_t _unused1[8]; + + uint32_t volume_space_LSB; + uint32_t volume_space_MSB; + + uint8_t _unused2[32]; + + uint16_t volume_set_LSB; + uint16_t volume_set_MSB; + + uint16_t volume_seq_LSB; + uint16_t volume_seq_MSB; + + uint16_t logical_block_size_LSB; + uint16_t logical_block_size_MSB; + + uint32_t path_table_size_LSB; + uint32_t path_table_size_MSB; + + uint32_t path_table_LSB; + uint32_t optional_path_table_LSB; + + uint32_t path_table_MSB; + uint32_t optional_path_table_MSB; + + /* iso_9660_directory_entry_t */ + char root[34]; + + char volume_set_id[128]; + char volume_publisher[128]; + char data_preparer[128]; + char application_id[128]; + + char copyright_file[38]; + char abstract_file[36]; + char bibliographic_file[37]; + + iso_9660_datetime_t creation; + iso_9660_datetime_t modification; + iso_9660_datetime_t expiration; + iso_9660_datetime_t effective; + + uint8_t file_structure_version; + uint8_t _unused_3; + + char application_use[]; +} __attribute__((packed)) iso_9660_volume_descriptor_t; + +static void file_from_dir_entry(iso_9660_fs_t * this, size_t sector, iso_9660_directory_entry_t * dir, size_t offset, fs_node_t * fs); + +#define CACHE_SIZE 64 + +static void read_sector(iso_9660_fs_t * this, uint32_t sector_id, char * buffer) { + if (this->cache) { + void * sector_id_v = (void *)sector_id; + if (hashmap_has(this->cache, sector_id_v)) { + memcpy(buffer,hashmap_get(this->cache, sector_id_v), this->block_size); + + node_t * me = list_find(this->lru, sector_id_v); + list_delete(this->lru, me); + list_append(this->lru, me); + + } else { + if (this->lru->length > CACHE_SIZE) { + node_t * l = list_dequeue(this->lru); + free(hashmap_get(this->cache, l->value)); + hashmap_remove(this->cache, l->value); + free(l); + } + read_fs(this->block_device, sector_id * this->block_size, this->block_size, (uint8_t *)buffer); + char * buf = malloc(this->block_size); + memcpy(buf, buffer, this->block_size); + hashmap_set(this->cache, sector_id_v, buf); + list_insert(this->lru, sector_id_v); + } + } else { + read_fs(this->block_device, sector_id * this->block_size, this->block_size, (uint8_t *)buffer); + } +} + +static void inplace_lower(char * string) { + while (*string) { + if (*string >= 'A' && *string <= 'Z') { + *string += ('a' - 'A'); + } + string++; + } +} + +static void open_iso(fs_node_t *node, unsigned int flags) { + /* Nothing to do here */ +} + +static void close_iso(fs_node_t *node) { + /* Nothing to do here */ +} + +static struct dirent * readdir_iso(fs_node_t *node, uint32_t index) { + if (index == 0) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, "."); + return out; + } + + if (index == 1) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, ".."); + return out; + } + + iso_9660_fs_t * this = node->device; + char * buffer = malloc(this->block_size); + read_sector(this, node->inode, buffer); + iso_9660_directory_entry_t * root_entry = (iso_9660_directory_entry_t *)(buffer + node->impl); + + debug_print(INFO, "[iso] Reading directory for readdir; sector = %d, offset = %d", node->inode, node->impl); + + uint8_t * root_data = malloc(root_entry->extent_length_LSB); + uint8_t * offset = root_data; + size_t sector_offset = 0; + size_t length_to_read = root_entry->extent_length_LSB; + while (length_to_read) { + read_sector(this, root_entry->extent_start_LSB + sector_offset, (char*)offset); + if (length_to_read >= this->block_size) { + offset += this->block_size; + sector_offset += 1; + length_to_read -= this->block_size; + } else { + break; + } + } + + debug_print(INFO, "[iso] Done, want index = %d", index); + + /* Examine directory */ + offset = root_data; + + unsigned int i = 0; + struct dirent *dirent = malloc(sizeof(struct dirent)); + fs_node_t * out = malloc(sizeof(fs_node_t)); + memset(dirent, 0, sizeof(struct dirent)); + while (1) { + iso_9660_directory_entry_t * dir = (iso_9660_directory_entry_t *)offset; + if (dir->length == 0) { + debug_print(INFO, "dir->length = %d", dir->length); + if ((size_t)(offset - root_data) < root_entry->extent_length_LSB) { + offset += 1; // this->block_size - ((uintptr_t)offset % this->block_size); + goto try_again; + } + break; + } + if (!(dir->flags & FLAG_HIDDEN)) { + debug_print(INFO, "[iso] Found file %d", i); + if (i == index) { + file_from_dir_entry(this, (root_entry->extent_start_LSB)+(offset - root_data)/this->block_size, dir, (offset - root_data) % this->block_size, out); + memcpy(&dirent->name, out->name, strlen(out->name)+1); + dirent->ino = out->inode; + goto cleanup; + } + i += 1; + } + offset += dir->length; +try_again: + if ((size_t)(offset - root_data) > root_entry->extent_length_LSB) break; + } + + debug_print(INFO, "offset = %x; root_data = %x; extent = %x", offset, root_data, root_entry->extent_length_LSB); + + free(dirent); + dirent = NULL; + +cleanup: + free(root_data); + free(buffer); + free(out); + return dirent; +} + +static uint32_t read_iso(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) { + iso_9660_fs_t * this = node->device; + char * tmp = malloc(this->block_size); + read_sector(this, node->inode, tmp); + iso_9660_directory_entry_t * root_entry = (iso_9660_directory_entry_t *)(tmp + node->impl); + + uint32_t end; + /* We can do this in a single underlying read to the filesystem */ + if (offset + size > root_entry->extent_length_LSB) { + end = root_entry->extent_length_LSB; + } else { + end = offset + size; + } + uint32_t size_to_read = end - offset; + + read_fs(this->block_device, root_entry->extent_start_LSB * this->block_size + offset, size_to_read, (uint8_t *)buffer); + + free(tmp); + return size_to_read; +} + +static fs_node_t * finddir_iso(fs_node_t *node, char *name) { + iso_9660_fs_t * this = node->device; + char * buffer = malloc(this->block_size); + read_sector(this, node->inode, buffer); + iso_9660_directory_entry_t * root_entry = (iso_9660_directory_entry_t *)(buffer + node->impl); + + uint8_t * root_data = malloc(root_entry->extent_length_LSB); + uint8_t * offset = root_data; + size_t sector_offset = 0; + size_t length_to_read = root_entry->extent_length_LSB; + while (length_to_read) { + read_sector(this, root_entry->extent_start_LSB + sector_offset, (char*)offset); + if (length_to_read >= this->block_size) { + offset += this->block_size; + sector_offset += 1; + length_to_read -= this->block_size; + } else { + break; + } + } + + /* Examine directory */ + offset = root_data; + + fs_node_t * out = malloc(sizeof(fs_node_t)); + while (1) { + iso_9660_directory_entry_t * dir = (iso_9660_directory_entry_t *)offset; + if (dir->length == 0) { + if ((size_t)(offset - root_data) < root_entry->extent_length_LSB) { + offset += 1; // this->block_size - ((uintptr_t)offset % this->block_size); + goto try_next_finddir; + } + break; + } + if (!(dir->flags & FLAG_HIDDEN)) { + memset(out, 0, sizeof(fs_node_t)); + file_from_dir_entry(this, (root_entry->extent_start_LSB)+(offset - root_data)/this->block_size, dir, (offset - root_data) % this->block_size, out); + + if (!strcmp(out->name, name)) { + goto cleanup; /* found it */ + } + + } + offset += dir->length; +try_next_finddir: + if ((size_t)(offset - root_data) > root_entry->extent_length_LSB) break; + } + + free(out); + out = NULL; + +cleanup: + free(root_data); + free(buffer); + return out; +} + +static void file_from_dir_entry(iso_9660_fs_t * this, size_t sector, iso_9660_directory_entry_t * dir, size_t offset, fs_node_t * fs) { + fs->device = this; + fs->inode = sector; /* Sector the file is in */ + fs->impl = offset; /* Offset */ + + char * file_name = malloc(dir->name_len + 1); + memcpy(file_name, dir->name, dir->name_len); + file_name[dir->name_len] = 0; + inplace_lower(file_name); + char * dot = strchr(file_name, '.'); + if (!dot) { + /* It's a directory. */ + } else { + char * ext = dot + 1; + char * semi = strchr(ext, ';'); + if (semi) { + *semi = 0; + } + if (strlen(ext) == 0) { + *dot = 0; + } else { + char * derp = ext; + while (*derp == '.') derp++; + if (derp != ext) { + memmove(ext, derp, strlen(derp)+1); + } + } + } + memcpy(fs->name, file_name, strlen(file_name)+1); + free(file_name); + + fs->uid = 0; + fs->gid = 0; + fs->length = dir->extent_length_LSB; + fs->mask = 0444; + fs->nlink = 0; /* Unsupported */ + if (dir->flags & FLAG_DIRECTORY) { + fs->flags = FS_DIRECTORY; + fs->readdir = readdir_iso; + fs->finddir = finddir_iso; + } else { + fs->flags = FS_FILE; + fs->read = read_iso; + } + /* Other things not supported */ + /* TODO actually get these from the CD into Unix time */ + fs->atime = now(); + fs->mtime = now(); + fs->ctime = now(); + + fs->open = open_iso; + fs->close = close_iso; +} + +static fs_node_t * iso_fs_mount(char * device, char * mount_path) { + char * arg = strdup(device); + char * argv[10]; + int argc = tokenize(arg, ",", argv); + + fs_node_t * dev = kopen(argv[0], 0); + if (!dev) { + debug_print(ERROR, "failed to open %s", device); + return NULL; + } + + int cache = 1; + + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i],"nocache")) { + cache = 0; + } else { + debug_print(WARNING, "Unrecognized option to iso driver: %s", argv[i]); + } + } + + if (!dev) { + debug_print(ERROR, "failed to open %s", argv[0]); + free(arg); + return NULL; + } + + iso_9660_fs_t * this = malloc(sizeof(iso_9660_fs_t)); + this->block_device = dev; + this->block_size = ISO_SECTOR_SIZE; + if (cache) { + this->cache = hashmap_create_int(10); + this->lru = list_create(); + } else { + this->cache = NULL; + } + + /* Probably want to put a block cache on this like EXT2 driver does; or do that in the ATAPI layer... */ + + debug_print(WARNING, "ISO 9660 file system driver mounting %s to %s", device, mount_path); + + /* Read the volume descriptors */ + uint8_t * tmp = malloc(ISO_SECTOR_SIZE); + int i = 0x10; + int found = 0; + while (1) { + read_sector(this,i,(char*)tmp); + if (tmp[0] == 0x00) { + debug_print(WARNING, " Boot Record"); + } else if (tmp[0] == 0x01) { + debug_print(WARNING, " Primary Volume Descriptor"); + found = 1; + break; + } else if (tmp[0] == 0x02) { + debug_print(WARNING, " Secondary Volume Descriptor"); + } else if (tmp[0] == 0x03) { + debug_print(WARNING, " Volume Partition Descriptor"); + } + if (tmp[0] == 0xFF) break; + i++; + } + + if (!found) { + debug_print(WARNING, "No primary volume descriptor?"); + free(arg); + return NULL; + } + + iso_9660_volume_descriptor_t * root = (iso_9660_volume_descriptor_t *)tmp; + + debug_print(WARNING, " Volume space: %d", root->volume_space_LSB); + debug_print(WARNING, " Volume set: %d", root->volume_set_LSB); + debug_print(WARNING, " Volume seq: %d", root->volume_seq_LSB); + debug_print(WARNING, " Block size: %d", root->logical_block_size_LSB); + debug_print(WARNING, " Path table size: %d", root->path_table_size_LSB); + debug_print(WARNING, " Path table loc: %d", root->path_table_LSB); + + iso_9660_directory_entry_t * root_entry = (iso_9660_directory_entry_t *)&root->root; + + debug_print(WARNING, "ISO root info:"); + debug_print(WARNING, " Entry len: %d", root_entry->length); + debug_print(WARNING, " File start: %d", root_entry->extent_start_LSB); + debug_print(WARNING, " File len: %d", root_entry->extent_length_LSB); + debug_print(WARNING, " Is a directory: %s", (root_entry->flags & FLAG_DIRECTORY) ? "yes" : "no?"); + debug_print(WARNING, " Interleave units: %d", root_entry->interleave_units); + debug_print(WARNING, " Interleave gap: %d", root_entry->interleave_gap); + debug_print(WARNING, " Volume Seq: %d", root_entry->volume_seq_LSB); + + fs_node_t * fs = malloc(sizeof(fs_node_t)); + memset(fs, 0, sizeof(fs_node_t)); + file_from_dir_entry(this, i, root_entry, 156, fs); + + free(arg); + return fs; +} + +static int init(void) { + vfs_register("iso", iso_fs_mount); + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(iso9660, init, fini); diff --git a/modules/lfbvideo.c b/modules/lfbvideo.c new file mode 100644 index 00000000..422e6ec9 --- /dev/null +++ b/modules/lfbvideo.c @@ -0,0 +1,540 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + * + * Bochs VBE / QEMU vga=std Graphics Driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../apps/terminal-font.h" + +#define PREFERRED_VY 4096 +#define PREFERRED_B 32 +/* Generic (pre-set, 32-bit, linear frame buffer) */ +static void graphics_install_preset(uint16_t, uint16_t); + +uint16_t lfb_resolution_x = 0; +uint16_t lfb_resolution_y = 0; +uint16_t lfb_resolution_b = 0; +uint32_t lfb_resolution_s = 0; + +/* BOCHS / QEMU VBE Driver */ +static void graphics_install_bochs(uint16_t, uint16_t); +static void bochs_set_y_offset(uint16_t y); +static uint16_t bochs_current_scroll(void); + +static pid_t display_change_recipient = 0; + +void lfb_set_resolution(uint16_t x, uint16_t y); + +/* + * Address of the linear frame buffer. + * This can move, so it's a pointer instead of + * #define. + */ +uint8_t * lfb_vid_memory = (uint8_t *)0xE0000000; + +struct vid_size { + uint32_t width; + uint32_t height; +}; + +static int ioctl_vid(fs_node_t * node, int request, void * argp) { + /* TODO: Make this actually support multiple video devices */ + + switch (request) { + case IO_VID_WIDTH: + validate(argp); + *((size_t *)argp) = lfb_resolution_x; + return 0; + case IO_VID_HEIGHT: + validate(argp); + *((size_t *)argp) = lfb_resolution_y; + return 0; + case IO_VID_DEPTH: + validate(argp); + *((size_t *)argp) = lfb_resolution_b; + return 0; + case IO_VID_ADDR: + validate(argp); + *((uintptr_t *)argp) = (uintptr_t)lfb_vid_memory; + return 0; + case IO_VID_SIGNAL: + /* ioctl to register for a signal (vid device change? idk) on display change */ + display_change_recipient = getpid(); + return 0; + case IO_VID_SET: + validate(argp); + lfb_set_resolution(((struct vid_size *)argp)->width, ((struct vid_size *)argp)->height); + return 0; + case IO_VID_STRIDE: + *((size_t *)argp) = lfb_resolution_s; + return 0; + default: + return -1; /* TODO EINV... something or other */ + } +} + +static int vignette_at(int x, int y) { + int amount = 0; + int level = 100; + if (x < level) amount += (level - x); + if (x > lfb_resolution_x - level) amount += (level - (lfb_resolution_x - x)); + if (y < level) amount += (level - y); + if (y > lfb_resolution_y - level) amount += (level - (lfb_resolution_y - y)); + return amount; +} + +#define char_height 20 +#define char_width 9 + +static void set_point(int x, int y, uint32_t value) { + uint32_t * disp = (uint32_t *)lfb_vid_memory; + uint32_t * cell = &disp[y * (lfb_resolution_s / 4) + x]; + *cell = value; +} + +static void write_char(int x, int y, int val, uint32_t color) { + if (val > 128) { + val = 4; + } + uint16_t * c = large_font[val]; + for (uint8_t i = 0; i < char_height; ++i) { + for (uint8_t j = 0; j < char_width; ++j) { + if (c[i] & (1 << (15-j))) { + set_point(x+j,y+i,color); + } + } + } +} + +#define _RED(color) ((color & 0x00FF0000) / 0x10000) +#define _GRE(color) ((color & 0x0000FF00) / 0x100) +#define _BLU(color) ((color & 0x000000FF) / 0x1) +#define _ALP(color) ((color & 0xFF000000) / 0x1000000) +static void lfb_video_panic(char ** msgs) { + /* Desaturate the display */ + uint32_t * disp = (uint32_t *)lfb_vid_memory; + for (int y = 0; y < lfb_resolution_y; y++) { + for (int x = 0; x < lfb_resolution_x; x++) { + uint32_t * cell = &disp[y * (lfb_resolution_s / 4) + x]; + + int r = _RED(*cell); + int g = _GRE(*cell); + int b = _BLU(*cell); + + int l = 3 * r + 6 * g + 1 * b; + r = (l) / 10; + g = (l) / 10; + b = (l) / 10; + + r = r > 255 ? 255 : r; + g = g > 255 ? 255 : g; + b = b > 255 ? 255 : b; + + int amount = vignette_at(x,y); + r = (r - amount < 0) ? 0 : r - amount; + g = (g - amount < 0) ? 0 : g - amount; + b = (b - amount < 0) ? 0 : b - amount; + + *cell = 0xFF000000 + ((0xFF & r) * 0x10000) + ((0xFF & g) * 0x100) + ((0xFF & b) * 0x1); + } + } + + /* Now print the message, divided on line feeds, into the center of the screen */ + int num_entries = 0; + for (char ** m = msgs; *m; m++, num_entries++); + int y = (lfb_resolution_y - (num_entries * char_height)) / 2; + for (char ** message = msgs; *message; message++) { + int x = (lfb_resolution_x - (strlen(*message) * char_width)) / 2; + for (char * c = *message; *c; c++) { + write_char(x+1, y+1, *c, 0xFF000000); + write_char(x, y, *c, 0xFFFF0000); + x += char_width; + } + y += char_height; + } + +} + +static fs_node_t * lfb_video_device_create(void /* TODO */) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + sprintf(fnode->name, "fb0"); /* TODO */ + fnode->length = lfb_resolution_x * lfb_resolution_y * (lfb_resolution_b / 8); + fnode->flags = FS_BLOCKDEVICE; + fnode->mask = 0660; + fnode->ioctl = ioctl_vid; + return fnode; +} + +static void finalize_graphics(uint16_t x, uint16_t y, uint16_t b, uint32_t s) { + lfb_resolution_x = x; + lfb_resolution_s = s; + lfb_resolution_y = y; + lfb_resolution_b = b; + fs_node_t * fb_device = lfb_video_device_create(); + vfs_mount("/dev/fb0", fb_device); + debug_video_crash = lfb_video_panic; +} + +/* Bochs support {{{ */ +static uintptr_t current_scroll = 0; + +static void bochs_set_y_offset(uint16_t y) { + outports(0x1CE, 0x9); + outports(0x1CF, y); + current_scroll = y; +} + +static uint16_t bochs_current_scroll(void) { + return current_scroll; +} + +static void bochs_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) { + if ((v == 0x1234 && d == 0x1111) || + (v == 0x80EE && d == 0xBEEF)) { + uintptr_t t = pci_read_field(device, PCI_BAR0, 4); + if (t > 0) { + *((uint8_t **)extra) = (uint8_t *)(t & 0xFFFFFFF0); + } + } +} + +static void (*lfb_resolution_impl)(uint16_t,uint16_t) = NULL; + +void lfb_set_resolution(uint16_t x, uint16_t y) { + + if (lfb_resolution_impl) { + lfb_resolution_impl(x,y); + if (display_change_recipient) { + send_signal(display_change_recipient, SIGWINEVENT); + debug_print(WARNING, "Telling %d to SIGWINEVENT", display_change_recipient); + } + } + +} + +static void res_change_bochs(uint16_t x, uint16_t y) { + + outports(0x1CE, 0x04); + outports(0x1CF, 0x00); + /* Uh oh, here we go. */ + outports(0x1CE, 0x01); + outports(0x1CF, x); + /* Set Y resolution to 768 */ + outports(0x1CE, 0x02); + outports(0x1CF, y); + /* Set bpp to 32 */ + outports(0x1CE, 0x03); + outports(0x1CF, PREFERRED_B); + /* Set Virtual Height to stuff */ + outports(0x1CE, 0x07); + outports(0x1CF, PREFERRED_VY); + /* Turn it back on */ + outports(0x1CE, 0x04); + outports(0x1CF, 0x41); + + /* Read X to see if it's something else */ + outports(0x1CE, 0x01); + uint16_t new_x = inports(0x1CF); + if (x != new_x) { + x = new_x; + } + + lfb_resolution_x = x; + lfb_resolution_s = x * 4; + lfb_resolution_y = y; +} + + +static void graphics_install_bochs(uint16_t resolution_x, uint16_t resolution_y) { + uint32_t vid_memsize; + debug_print(NOTICE, "Setting up BOCHS/QEMU graphics controller..."); + + outports(0x1CE, 0x00); + uint16_t i = inports(0x1CF); + if (i < 0xB0C0 || i > 0xB0C6) { + return; + } + outports(0x1CF, 0xB0C4); + i = inports(0x1CF); + res_change_bochs(resolution_x, resolution_y); + resolution_x = lfb_resolution_x; /* may have changed */ + + pci_scan(bochs_scan_pci, -1, &lfb_vid_memory); + + lfb_resolution_impl = &res_change_bochs; + + if (lfb_vid_memory) { + /* Enable the higher memory */ + uintptr_t fb_offset = (uintptr_t)lfb_vid_memory; + for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + } + + goto mem_found; + } else { + /* XXX: Massive hack */ + + uint32_t * text_vid_mem = (uint32_t *)0xA0000; + text_vid_mem[0] = 0xA5ADFACE; + + for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) { + /* Enable the higher memory */ + for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + } + + /* Go find it */ + for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) { + if (((uintptr_t *)x)[0] == 0xA5ADFACE) { + lfb_vid_memory = (uint8_t *)x; + goto mem_found; + } + } + } + } + +mem_found: + outports(0x1CE, 0x0a); + i = inports(0x1CF); + if (i > 1) { + vid_memsize = (uint32_t)i * 64 * 1024; + } else { + vid_memsize = inportl(0x1CF); + } + debug_print(WARNING, "Video memory size is 0x%x", vid_memsize); + for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + vid_memsize; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + } + finalize_graphics(resolution_x, resolution_y, PREFERRED_B, resolution_x * 4); +} + +/* }}} end bochs support */ + +static void graphics_install_preset(uint16_t w, uint16_t h) { + debug_print(NOTICE, "Graphics were pre-configured (thanks, bootloader!), locating video memory..."); + uint16_t b = 32; /* If you are 24 bit, go away, we really do not support you. */ + + /* XXX: Massive hack */ + uint32_t * herp = (uint32_t *)0xA0000; + herp[0] = 0xA5ADFACE; + herp[1] = 0xFAF42943; + + if (lfb_vid_memory) { + for (uintptr_t i = (uintptr_t)lfb_vid_memory; i <= (uintptr_t)lfb_vid_memory + 0xFF0000; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + } + if (((uintptr_t *)lfb_vid_memory)[0] == 0xA5ADFACE && ((uintptr_t *)lfb_vid_memory)[1] == 0xFAF42943) { + debug_print(INFO, "Was able to locate video memory at 0x%x without dicking around.", lfb_vid_memory); + goto mem_found; + } + } + + for (int i = 2; i < 1000; i += 2) { + herp[i] = 0xFF00FF00; + herp[i+1] = 0x00FF00FF; + } + + for (uintptr_t fb_offset = 0xE0000000; fb_offset < 0xFF000000; fb_offset += 0x01000000) { + /* Enable the higher memory */ + for (uintptr_t i = fb_offset; i <= fb_offset + 0xFF0000; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + } + + /* Go find it */ + for (uintptr_t x = fb_offset; x < fb_offset + 0xFF0000; x += 0x1000) { + if (((uintptr_t *)x)[0] == 0xA5ADFACE && ((uintptr_t *)x)[1] == 0xFAF42943) { + lfb_vid_memory = (uint8_t *)x; + debug_print(INFO, "Had to futz around, but found video memory at 0x%x", lfb_vid_memory); + goto mem_found; + } + } + } + + for (int i = 2; i < 1000; i += 2) { + herp[i] = 0xFF00FF00; + herp[i+1] = 0xFF00FF00; + } + + debug_print(WARNING, "Failed to locate video memory. This could end poorly."); + +mem_found: + finalize_graphics(w,h,b,w*4); + +} + +#define SVGA_IO_BASE (vmware_io) +#define SVGA_IO_MUL 1 +#define SVGA_INDEX_PORT 0 +#define SVGA_VALUE_PORT 1 + +#define SVGA_REG_ID 0 +#define SVGA_REG_ENABLE 1 +#define SVGA_REG_WIDTH 2 +#define SVGA_REG_HEIGHT 3 +#define SVGA_REG_BITS_PER_PIXEL 7 +#define SVGA_REG_BYTES_PER_LINE 12 +#define SVGA_REG_FB_START 13 + +static uint32_t vmware_io = 0; + +static void vmware_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) { + if ((v == 0x15ad && d == 0x0405)) { + uintptr_t t = pci_read_field(device, PCI_BAR0, 4); + if (t > 0) { + *((uint8_t **)extra) = (uint8_t *)(t & 0xFFFFFFF0); + } + } +} + +static void vmware_write(int reg, int value) { + outportl(SVGA_IO_MUL * SVGA_INDEX_PORT + SVGA_IO_BASE, reg); + outportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE, value); +} + +static uint32_t vmware_read(int reg) { + outportl(SVGA_IO_MUL * SVGA_INDEX_PORT + SVGA_IO_BASE, reg); + return inportl(SVGA_IO_MUL * SVGA_VALUE_PORT + SVGA_IO_BASE); +} + +static void vmware_set_mode(uint16_t w, uint16_t h) { + vmware_write(SVGA_REG_ENABLE, 0); + vmware_write(SVGA_REG_ID, 0); + vmware_write(SVGA_REG_WIDTH, w); + vmware_write(SVGA_REG_HEIGHT, h); + vmware_write(SVGA_REG_BITS_PER_PIXEL, 32); + vmware_write(SVGA_REG_ENABLE, 1); + + uint32_t bpl = vmware_read(SVGA_REG_BYTES_PER_LINE); + + lfb_resolution_x = w; + lfb_resolution_s = bpl; + lfb_resolution_y = h; + +} + +static void graphics_install_vmware(uint16_t w, uint16_t h) { + debug_print(WARNING, "Please note that the `vmware` display driver is experimental."); + pci_scan(vmware_scan_pci, -1, &vmware_io); + + if (!vmware_io) { + debug_print(ERROR, "No vmware device found?"); + return; + } else { + debug_print(WARNING, "vmware io base: 0x%x", vmware_io); + } + + vmware_write(SVGA_REG_ID, 0); + vmware_write(SVGA_REG_WIDTH, w); + vmware_write(SVGA_REG_HEIGHT, h); + vmware_write(SVGA_REG_BITS_PER_PIXEL, 32); + vmware_write(SVGA_REG_ENABLE, 1); + + uint32_t bpl = vmware_read(SVGA_REG_BYTES_PER_LINE); + + lfb_resolution_impl = &vmware_set_mode; + + uint32_t fb_addr = vmware_read(SVGA_REG_FB_START); + debug_print(WARNING, "vmware fb address: 0x%x", fb_addr); + + uint32_t fb_size = vmware_read(15); + + debug_print(WARNING, "vmware fb size: 0x%x", fb_size); + + lfb_vid_memory = (uint8_t *)fb_addr; + + uintptr_t fb_offset = (uintptr_t)lfb_vid_memory; + for (uintptr_t i = fb_offset; i <= fb_offset + fb_size; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + } + + finalize_graphics(w,h,32,bpl); +} + +struct disp_mode { + int16_t x; + int16_t y; + int set; +}; + +static void auto_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) { + struct disp_mode * mode = extra; + if (mode->set) return; + if ((v == 0x1234 && d == 0x1111) || + (v == 0x80EE && d == 0xBEEF)) { + mode->set = 1; + graphics_install_bochs(mode->x, mode->y); + } else if ((v == 0x15ad && d == 0x0405)) { + mode->set = 1; + graphics_install_vmware(mode->x, mode->y); + } +} + + +static int init(void) { + + if (mboot_ptr->vbe_mode_info) { + lfb_vid_memory = (uint8_t *)((vbe_info_t *)(mboot_ptr->vbe_mode_info))->physbase; + } + + char * c; + if ((c = args_value("vid"))) { + debug_print(NOTICE, "Video mode requested: %s", c); + + char * arg = strdup(c); + char * argv[10]; + int argc = tokenize(arg, ",", argv); + + uint16_t x, y; + if (argc < 3) { + x = 1024; + y = 768; + } else { + x = atoi(argv[1]); + y = atoi(argv[2]); + } + + if (!strcmp(argv[0], "auto")) { + /* Attempt autodetection */ + debug_print(WARNING, "Autodetect is in beta, this may not work."); + struct disp_mode mode = {x,y,0}; + pci_scan(auto_scan_pci, -1, &mode); + if (!mode.set) { + graphics_install_preset(x,y); + } + } else if (!strcmp(argv[0], "qemu")) { + /* Bochs / Qemu Video Device */ + graphics_install_bochs(x,y); + } else if (!strcmp(argv[0],"preset")) { + graphics_install_preset(x,y); + } else if (!strcmp(argv[0],"vmware")) { + graphics_install_vmware(x,y); + } else { + debug_print(WARNING, "Unrecognized video adapter: %s", argv[0]); + } + + free(arg); + } + + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(lfbvideo, init, fini); diff --git a/modules/link.ld b/modules/link.ld new file mode 100644 index 00000000..f3cac6e8 --- /dev/null +++ b/modules/link.ld @@ -0,0 +1,20 @@ +SECTIONS +{ + .text : + { + *(.text*) + *(.rodata) + } + .data : + { + *(.data*) + } + .bss : + { + *(.bss*) + } + .moddeps : + { + *(.moddeps) + } +} diff --git a/modules/net.c b/modules/net.c new file mode 100644 index 00000000..1c8e6d62 --- /dev/null +++ b/modules/net.c @@ -0,0 +1,1586 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include +#include +#include + +static hashmap_t * dns_cache; +static list_t * dns_waiters = NULL; +static uint32_t _dns_server; + +static hashmap_t *_tcp_sockets = NULL; +static hashmap_t *_udp_sockets = NULL; + +static void parse_dns_response(fs_node_t * tty, void * last_packet); +static size_t write_dns_packet(uint8_t * buffer, size_t queries_len, uint8_t * queries); +size_t write_dhcp_request(uint8_t * buffer, uint8_t * ip); +static size_t write_arp_request(uint8_t * buffer, uint32_t ip); + +static uint8_t _gateway[6] = {255,255,255,255,255,255}; + +static struct netif _netif = {0}; + +static int tasklet_pid = 0; + +void init_netif_funcs(get_mac_func mac_func, get_packet_func get_func, send_packet_func send_func, char * device) { + _netif.get_mac = mac_func; + _netif.get_packet = get_func; + _netif.send_packet = send_func; + _netif.driver = device; + memcpy(_netif.hwaddr, _netif.get_mac(), sizeof(_netif.hwaddr)); + + if (!tasklet_pid) { + tasklet_pid = create_kernel_tasklet(net_handler, "[net]", NULL); + debug_print(NOTICE, "Network worker tasklet started with pid %d", tasklet_pid); + } +} + +struct netif * get_default_network_interface(void) { + return &_netif; +} + +uint32_t get_primary_dns(void) { + return _dns_server; +} + +uint32_t ip_aton(const char * in) { + char ip[16]; + char * c = ip; + uint32_t out[4]; + char * i; + memcpy(ip, in, strlen(in) < 15 ? strlen(in) + 1 : 15); + ip[15] = '\0'; + + i = (char *)lfind(c, '.'); + *i = '\0'; + out[0] = atoi(c); + c += strlen(c) + 1; + + i = (char *)lfind(c, '.'); + *i = '\0'; + out[1] = atoi(c); + c += strlen(c) + 1; + + i = (char *)lfind(c, '.'); + *i = '\0'; + out[2] = atoi(c); + c += strlen(c) + 1; + + out[3] = atoi(c); + + return ((out[0] << 24) | (out[1] << 16) | (out[2] << 8) | (out[3])); +} + +void ip_ntoa(uint32_t src_addr, char * out) { + sprintf(out, "%d.%d.%d.%d", + (src_addr & 0xFF000000) >> 24, + (src_addr & 0xFF0000) >> 16, + (src_addr & 0xFF00) >> 8, + (src_addr & 0xFF)); +} + +uint16_t calculate_ipv4_checksum(struct ipv4_packet * p) { + uint32_t sum = 0; + uint16_t * s = (uint16_t *)p; + + /* TODO: Checksums for options? */ + for (int i = 0; i < 10; ++i) { + sum += ntohs(s[i]); + } + + if (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + + return ~(sum & 0xFFFF) & 0xFFFF; +} + +uint16_t calculate_tcp_checksum(struct tcp_check_header * p, struct tcp_header * h, void * d, size_t payload_size) { + uint32_t sum = 0; + uint16_t * s = (uint16_t *)p; + + /* TODO: Checksums for options? */ + for (int i = 0; i < 6; ++i) { + sum += ntohs(s[i]); + if (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + } + + s = (uint16_t *)h; + for (int i = 0; i < 10; ++i) { + sum += ntohs(s[i]); + if (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + } + + uint16_t d_words = payload_size / 2; + + s = (uint16_t *)d; + for (unsigned int i = 0; i < d_words; ++i) { + sum += ntohs(s[i]); + if (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + } + + if (d_words * 2 != payload_size) { + uint8_t * t = (uint8_t *)d; + uint8_t tmp[2]; + tmp[0] = t[d_words * sizeof(uint16_t)]; + tmp[1] = 0; + + uint16_t * f = (uint16_t *)tmp; + + sum += ntohs(f[0]); + if (sum > 0xFFFF) { + sum = (sum >> 16) + (sum & 0xFFFF); + } + } + + return ~(sum & 0xFFFF) & 0xFFFF; +} + +static struct dirent * readdir_netfs(fs_node_t *node, uint32_t index) { + if (index == 0) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, "."); + return out; + } + + if (index == 1) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, ".."); + return out; + } + + index -= 2; + return NULL; +} + +size_t dns_name_to_normal_name(struct dns_packet * dns, size_t offset, char * buf) { + uint8_t * bytes = (uint8_t *)dns; + size_t i = 0; + + while (1) { + uint8_t c = bytes[offset]; + if (c == 0) break; + if (c >= 0xC0) { + uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1]; + i += dns_name_to_normal_name(dns, ref, &buf[i]); + return i; + } + offset++; + + for (size_t j = 0; j < c; j++) { + buf[i] = bytes[offset]; + i++; + offset++; + } + buf[i] = '.'; + i++; + buf[i] = '\0'; + } + if (i == 0) return 0; + + buf[i-1] = '\0'; + return i-1; +} + +size_t get_dns_name(char * buffer, struct dns_packet * dns, size_t offset) { + uint8_t * bytes = (uint8_t *)dns; + while (1) { + uint8_t c = bytes[offset]; + if (c == 0) { + offset++; + return offset; + } else if (c >= 0xC0) { + uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1]; + get_dns_name(buffer, dns, ref); + offset++; + offset++; + return offset; + } else { + for (int i = 0; i < c; ++i) { + *buffer = bytes[offset+1+i]; + buffer++; + *buffer = '\0'; + } + *buffer = '.'; + buffer++; + *buffer = '\0'; + offset += c + 1; + } + } +} + +size_t print_dns_name(fs_node_t * tty, struct dns_packet * dns, size_t offset) { + uint8_t * bytes = (uint8_t *)dns; + while (1) { + uint8_t c = bytes[offset]; + if (c == 0) { + offset++; + return offset; + } else if (c >= 0xC0) { + uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1]; + print_dns_name(tty, dns, ref); + offset++; + offset++; + return offset; + } else { + for (int i = 0; i < c; ++i) { + fprintf(tty,"%c",bytes[offset+1+i]); + } + fprintf(tty,"."); + offset += c + 1; + } + } +} + +static int is_ip(char * name) { + + unsigned int dot_count = 0; + unsigned int t = 0; + + for (char * c = name; *c != '\0'; ++c) { + if ((*c < '0' || *c > '9') && (*c != '.')) return 0; + if (*c == '.') { + if (t > 255) return 0; + dot_count++; + t = 0; + } else { + t *= 10; + t += *c - '0'; + } + if (dot_count == 4) return 0; + } + if (dot_count != 3) return 0; + + return 1; +} + +static char read_a_byte(struct socket * stream, int * status) { + static char * foo = NULL; + static char * read_ptr = NULL; + static int have_bytes = 0; + if (!foo) foo = malloc(4096); + while (!have_bytes) { + memset(foo, 0x00, 4096); + have_bytes = net_recv(stream, (uint8_t *)foo, 4096); + if (have_bytes == 0) { + *status = 1; + return 0; + } + debug_print(WARNING, "Received %d bytes...", have_bytes); + read_ptr = foo; + } + + char ret = *read_ptr; + + have_bytes -= 1; + read_ptr++; + + return ret; +} + + +static char * fgets(char * buf, int size, struct socket * stream) { + char * x = buf; + int collected = 0; + + while (collected < size) { + + int status = 0; + + *x = read_a_byte(stream, &status); + + if (status == 1) { + return buf; + } + + collected++; + + if (*x == '\n') break; + + x++; + } + + x++; + *x = '\0'; + return buf; +} + +static void socket_alert_waiters(struct socket * sock) { + if (sock->alert_waiters) { + while (sock->alert_waiters->head) { + node_t * node = list_dequeue(sock->alert_waiters); + process_t * p = node->value; + process_alert_node(p, sock); + free(node); + } + } +} + + +static int socket_check(fs_node_t * node) { + struct socket * sock = node->device; + + if (sock->packet_queue->length > 0) { + return 0; + } + + return 1; +} + +static int socket_wait(fs_node_t * node, void * process) { + struct socket * sock = node->device; + + if (!list_find(sock->alert_waiters, process)) { + list_insert(sock->alert_waiters, process); + } + + list_insert(((process_t *)process)->node_waits, sock); + return 0; +} + +static uint32_t socket_read(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) { + /* Sleep until we have something to receive */ +#if 0 + fgets((char *)buffer, size, node->device); + return strlen((char *)buffer); +#else + return net_recv(node->device, buffer, size); +#endif +} +static uint32_t socket_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) { + /* Add the packet to the appropriate interface queue and send it off. */ + + net_send((struct socket *)node->device, buffer, size, 0); + return size; +} + +uint16_t next_ephemeral_port(void) { + static uint16_t next = 49152; + + if (next == 0) { + assert(0 && "All out of ephemeral ports, halting this time."); + } + + uint16_t out = next; + next++; + + if (next == 0) { + debug_print(WARNING, "Ran out of ephemeral ports - next time I'm going to bail."); + debug_print(WARNING, "You really need to implement a bitmap here."); + } + + return out; +} + +fs_node_t * socket_ipv4_tcp_create(uint32_t dest, uint16_t target_port, uint16_t source_port) { + + /* Okay, first step is to get us added to the table so we can receive syns. */ + + return NULL; + +} + +static int gethost(char * name, uint32_t * ip) { + if (is_ip(name)) { + debug_print(WARNING, " IP: %x", ip_aton(name)); + *ip = ip_aton(name); + return 0; + } else { + if (hashmap_has(dns_cache, name)) { + *ip = ip_aton(hashmap_get(dns_cache, name)); + debug_print(WARNING, " In Cache: %s → %x", name, ip); + return 0; + } else { + debug_print(WARNING, " Not in cache: %s", name); + debug_print(WARNING, " Still needs look up."); + char * xname = strdup(name); + char * queries = malloc(1024); + queries[0] = '\0'; + char * subs[10]; /* 10 is probably not the best number. */ + int argc = tokenize(xname, ".", subs); + int n = 0; + for (int i = 0; i < argc; ++i) { + debug_print(WARNING, "dns [%d]%s", strlen(subs[i]), subs[i]); + sprintf(&queries[n], "%c%s", strlen(subs[i]), subs[i]); + n += strlen(&queries[n]); + } + int c = strlen(queries) + 1; + queries[c+0] = 0x00; + queries[c+1] = 0x01; /* A */ + queries[c+2] = 0x00; + queries[c+3] = 0x01; /* IN */ + free(xname); + + debug_print(WARNING, "Querying..."); + + void * tmp = malloc(1024); + size_t packet_size = write_dns_packet(tmp, c + 4, (uint8_t *)queries); + free(queries); + + _netif.send_packet(tmp, packet_size); + free(tmp); + + /* wait for response */ + if (current_process->id != tasklet_pid) { + sleep_on(dns_waiters); + } + if (hashmap_has(dns_cache, name)) { + *ip = ip_aton(hashmap_get(dns_cache, name)); + debug_print(WARNING, " Now in cache: %s → %x", name, ip); + return 0; + } else { + if (current_process->id == tasklet_pid) { + debug_print(WARNING, "Query hasn't returned yet, but we're in the network thread, so we need to yield."); + return 2; + } + gethost(name,ip); + return 1; + } + } + } +} + + +/* TODO: socket_close - TCP close; UDP... just clean us up */ +/* TODO: socket_open - idk, whatever */ + +static fs_node_t * finddir_netfs(fs_node_t * node, char * name) { + /* Should essentially find anything. */ + debug_print(WARNING, "Need to look up domain or check if is IP: %s", name); + /* Block until lookup is complete */ + + int port = 80; + char * colon; + if ((colon = strstr(name, ":"))) { + /* Port numbers */ + *colon = '\0'; + colon++; + port = atoi(colon); + } + + uint32_t ip = 0; + if (gethost(name, &ip)) return NULL; + + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, name); + fnode->mask = 0666; + fnode->flags = FS_CHARDEVICE; + fnode->read = socket_read; + fnode->write = socket_write; + fnode->device = (void *)net_open(SOCK_STREAM); + fnode->selectcheck = socket_check; + fnode->selectwait = socket_wait; + + net_connect((struct socket *)fnode->device, ip, port); + + return fnode; +} + +static int ioctl_netfs(fs_node_t * node, int request, void * argp) { + switch (request) { + case 0x5000: { + /* */ + debug_print(INFO, "DNS query from userspace"); + void ** x = (void **)argp; + char * host = x[0]; + uint32_t * ip = x[1]; + /* TODO: Validate */ + return gethost(host, ip); + } + } + return 0; +} + +static size_t write_dns_packet(uint8_t * buffer, size_t queries_len, uint8_t * queries) { + size_t offset = 0; + size_t payload_size = sizeof(struct dns_packet) + queries_len; + + /* Then, let's write an ethernet frame */ + struct ethernet_packet eth_out = { + .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], + _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, + .destination = BROADCAST_MAC, + .type = htons(0x0800), + }; + + memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); + offset += sizeof(struct ethernet_packet); + + /* Prepare the IPv4 header */ + uint16_t _length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + payload_size); + uint16_t _ident = htons(1); + + struct ipv4_packet ipv4_out = { + .version_ihl = ((0x4 << 4) | (0x5 << 0)), /* 4 = ipv4, 5 = no options */ + .dscp_ecn = 0, /* not setting either of those */ + .length = _length, + .ident = _ident, + .flags_fragment = 0, + .ttl = 0x40, + .protocol = IPV4_PROT_UDP, + .checksum = 0, /* fill this in later */ + .source = htonl(_netif.source), + .destination = htonl(_dns_server), + }; + + uint16_t checksum = calculate_ipv4_checksum(&ipv4_out); + ipv4_out.checksum = htons(checksum); + + memcpy(&buffer[offset], &ipv4_out, sizeof(struct ipv4_packet)); + offset += sizeof(struct ipv4_packet); + + uint16_t _udp_source = htons(50053); /* Use an ephemeral port */ + uint16_t _udp_destination = htons(53); + uint16_t _udp_length = htons(sizeof(struct udp_packet) + payload_size); + + /* Now let's build a UDP packet */ + struct udp_packet udp_out = { + .source_port = _udp_source, + .destination_port = _udp_destination, + .length = _udp_length, + .checksum = 0, + }; + + /* XXX calculate checksum here */ + + memcpy(&buffer[offset], &udp_out, sizeof(struct udp_packet)); + offset += sizeof(struct udp_packet); + + /* DNS header */ + struct dns_packet dns_out = { + .qid = htons(0), + .flags = htons(0x0100), /* Standard query */ + .questions = htons(1), /* 1 question */ + .answers = htons(0), + .authorities = htons(0), + .additional = htons(0), + }; + + memcpy(&buffer[offset], &dns_out, sizeof(struct dns_packet)); + offset += sizeof(struct dns_packet); + + memcpy(&buffer[offset], queries, queries_len); + offset += queries_len; + + return offset; +} + +static int net_send_ether(struct socket *socket, struct netif* netif, uint16_t ether_type, void* payload, uint32_t payload_size) { + struct ethernet_packet *eth = malloc(sizeof(struct ethernet_packet) + payload_size); + memcpy(eth->source, netif->hwaddr, sizeof(eth->source)); + //memset(eth->destination, 0xFF, sizeof(eth->destination)); + memcpy(eth->destination, _gateway, sizeof(_gateway)); + eth->type = htons(ether_type); + + if (payload_size) { + memcpy(eth->payload, payload, payload_size); + } + + netif->send_packet((uint8_t*)eth, sizeof(struct ethernet_packet) + payload_size); + + free(eth); + + return 1; // yolo +} + +static int net_send_ip(struct socket *socket, int proto, void* payload, uint32_t payload_size) { + struct ipv4_packet *ipv4 = malloc(sizeof(struct ipv4_packet) + payload_size); + + uint16_t _length = htons(sizeof(struct ipv4_packet) + payload_size); + uint16_t _ident = htons(1); + + ipv4->version_ihl = ((0x4 << 4) | (0x5 << 0)); /* 4 = ipv4, 5 = no options */ + ipv4->dscp_ecn = 0; /* not setting either of those */ + ipv4->length = _length; + ipv4->ident = _ident; + ipv4->flags_fragment = 0; + ipv4->ttl = 0x40; + ipv4->protocol = proto; + ipv4->checksum = 0; // Fill in later */ + ipv4->source = htonl(_netif.source), + ipv4->destination = htonl(socket->ip); + + uint16_t checksum = calculate_ipv4_checksum(ipv4); + ipv4->checksum = htons(checksum); + + if (proto == IPV4_PROT_TCP) { + // Need to calculate TCP checksum + struct tcp_check_header check_hd = { + .source = ipv4->source, + .destination = ipv4->destination, + .zeros = 0, + .protocol = 6, + .tcp_len = htons(payload_size), + }; + + // debug_print(WARNING, "net_send_ip: Payload size: %d\n", payload_size); + struct tcp_header* tcp_hdr = (struct tcp_header*)payload; + // debug_print(WARNING, "net_send_ip: Header len htons: %d\n", TCP_HEADER_LENGTH_FLIPPED(tcp_hdr)); + size_t orig_payload_size = payload_size - TCP_HEADER_LENGTH_FLIPPED(tcp_hdr); + + uint16_t chk = calculate_tcp_checksum(&check_hd, tcp_hdr, tcp_hdr->payload, orig_payload_size); + tcp_hdr->checksum = htons(chk); + } + + if (payload) { + memcpy(ipv4->payload, payload, payload_size); + free(payload); + } + + // TODO: netif should not be a global thing. But the route should be looked up here and a netif object created/returned + int out = net_send_ether(socket, &_netif, ETHERNET_TYPE_IPV4, ipv4, sizeof(struct ipv4_packet) + payload_size); + free(ipv4); + return out; +} + +static int net_send_tcp(struct socket *socket, uint16_t flags, uint8_t * payload, uint32_t payload_size) { + struct tcp_header *tcp = malloc(sizeof(struct tcp_header) + payload_size); + + tcp->source_port = htons(socket->port_recv); + tcp->destination_port = htons(socket->port_dest); + tcp->seq_number = htonl(socket->proto_sock.tcp_socket.seq_no); + tcp->ack_number = flags & (TCP_FLAGS_ACK) ? htonl(socket->proto_sock.tcp_socket.ack_no) : 0; + tcp->flags = htons(0x5000 ^ (flags & 0xFF)); + tcp->window_size = htons(1548-54); + tcp->checksum = 0; // Fill in later + tcp->urgent = 0; + + if ((flags & 0xff) == TCP_FLAGS_SYN) { + // If only SYN set, expected ACK will be 1 despite no payload + socket->proto_sock.tcp_socket.seq_no += 1; + } else { + socket->proto_sock.tcp_socket.seq_no += payload_size; + } + + if (payload) { + memcpy(tcp->payload, payload, payload_size); + } + + return net_send_ip(socket, IPV4_PROT_TCP, tcp, sizeof(struct tcp_header) + payload_size); +} + +struct socket* net_open(uint32_t type) { + // This is a socket() call + struct socket *sock = malloc(sizeof(struct socket)); + memset(sock, 0, sizeof(struct socket)); + sock->sock_type = type; + + return sock; +} + +int net_close(struct socket* socket) { + // socket->is_connected; + socket->status = 1; /* Disconnected */ + wakeup_queue(socket->packet_wait); + socket_alert_waiters(socket); + return 1; +} + +int net_send(struct socket* socket, uint8_t* payload, size_t payload_size, int flags) { + return net_send_tcp(socket, TCP_FLAGS_ACK | TCP_FLAGS_PSH, payload, payload_size); +} + +size_t net_recv(struct socket* socket, uint8_t* buffer, size_t len) { + tcpdata_t *tcpdata = NULL; + node_t *node = NULL; + + debug_print(INFO, "0x%x [socket]", socket); + + size_t offset = 0; + size_t size_to_read = 0; + + do { + + if (socket->bytes_available) { + tcpdata = socket->current_packet; + } else { + spin_lock(socket->packet_queue_lock); + do { + if (socket->packet_queue->length > 0) { + node = list_dequeue(socket->packet_queue); + spin_unlock(socket->packet_queue_lock); + break; + } else { + if (socket->status == 1) { + spin_unlock(socket->packet_queue_lock); + debug_print(WARNING, "Socket closed, done reading."); + return 0; + } + spin_unlock(socket->packet_queue_lock); + sleep_on(socket->packet_wait); + spin_lock(socket->packet_queue_lock); + } + } while (1); + + tcpdata = node->value; + socket->bytes_available = tcpdata->payload_size; + socket->bytes_read = 0; + free(node); + } + + size_to_read = MIN(len, offset + socket->bytes_available); + + if (tcpdata->payload != 0) { + memcpy(buffer + offset, tcpdata->payload + socket->bytes_read, size_to_read); + } + + offset += size_to_read; + + if (size_to_read < socket->bytes_available) { + socket->bytes_available = socket->bytes_available - size_to_read; + socket->bytes_read = size_to_read; + socket->current_packet = tcpdata; + } else { + socket->bytes_available = 0; + socket->current_packet = NULL; + free(tcpdata->payload); + free(tcpdata); + } + + + } while (!size_to_read); + + + return size_to_read; +} + +static void net_handle_tcp(struct tcp_header * tcp, size_t length) { + + size_t data_length = length - TCP_HEADER_LENGTH_FLIPPED(tcp); + + /* Find socket */ + if (hashmap_has(_tcp_sockets, (void *)ntohs(tcp->destination_port))) { + struct socket *socket = hashmap_get(_tcp_sockets, (void *)ntohs(tcp->destination_port)); + + if (socket->status == 1) { + debug_print(ERROR, "Socket is closed, but still receiving packets. Should send FIN. socket=0x%x", socket); + return; + } + + if (socket->proto_sock.tcp_socket.seq_no != ntohl(tcp->ack_number)) { + // Drop packet + debug_print(WARNING, "Dropping packet. Expected ack: %d | Got ack: %d", + socket->proto_sock.tcp_socket.seq_no, ntohl(tcp->ack_number)); + return; + } + + if ((htons(tcp->flags) & TCP_FLAGS_SYN) && (htons(tcp->flags) & TCP_FLAGS_ACK)) { + socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length + 1; + net_send_tcp(socket, TCP_FLAGS_ACK, NULL, 0); + wakeup_queue(socket->proto_sock.tcp_socket.is_connected); + } else if (htons(tcp->flags) & TCP_FLAGS_RES) { + /* Reset doesn't necessarily mean close. */ + debug_print(WARNING, "net_handle_tcp: Received RST - socket closing"); + net_close(socket); + return; + } else { + // Store a copy of the layer 5 data for a userspace recv() call + tcpdata_t *tcpdata = malloc(sizeof(tcpdata_t)); + tcpdata->payload_size = length - TCP_HEADER_LENGTH_FLIPPED(tcp); + + if (tcpdata->payload_size == 0) { + if (htons(tcp->flags) & TCP_FLAGS_FIN) { + /* We should make sure we finish sending before closing. */ + debug_print(WARNING, "net_handle_tcp: Received FIN - socket closing with SYNACK"); + socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length + 1; + net_send_tcp(socket, TCP_FLAGS_ACK | TCP_FLAGS_FIN, NULL, 0); + wakeup_queue(socket->proto_sock.tcp_socket.is_connected); + net_close(socket); + } + free(tcpdata); + return; + } + + // debug_print(WARNING, "net_handle_tcp: payload length: %d\n", length); + // debug_print(WARNING, "net_handle_tcp: flipped tcp flags hdr len: %d\n", TCP_HEADER_LENGTH_FLIPPED(tcp)); + // debug_print(WARNING, "net_handle_tcp: tcpdata->payload_size: %d\n", tcpdata->payload_size); + + if (tcpdata->payload_size > 0) { + tcpdata->payload = malloc(tcpdata->payload_size); + memcpy(tcpdata->payload, tcp->payload, tcpdata->payload_size); + } else { + tcpdata->payload = NULL; + } + + socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length; + + if ((htons(tcp->flags) & TCP_FLAGS_SYN) && (htons(tcp->flags) & TCP_FLAGS_ACK) && data_length == 0) { + socket->proto_sock.tcp_socket.ack_no += 1; + } + + socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + tcpdata->payload_size; + + spin_lock(socket->packet_queue_lock); + list_insert(socket->packet_queue, tcpdata); + spin_unlock(socket->packet_queue_lock); + + // Send acknowledgement of receiving data + net_send_tcp(socket, TCP_FLAGS_ACK, NULL, 0); + + wakeup_queue(socket->packet_wait); + socket_alert_waiters(socket); + + if (htons(tcp->flags) & TCP_FLAGS_FIN) { + /* We should make sure we finish sending before closing. */ + debug_print(WARNING, "net_handle_tcp: Received FIN - socket closing with SYNACK"); + socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length + 1; + net_send_tcp(socket, TCP_FLAGS_ACK | TCP_FLAGS_FIN, NULL, 0); + wakeup_queue(socket->proto_sock.tcp_socket.is_connected); + net_close(socket); + } + } + } else { + debug_print(WARNING, "net_handle_tcp: Received packet not associated with a socket!"); + } +} + +static void net_handle_udp(struct udp_packet * udp, size_t length) { + + // size_t data_length = length - sizeof(struct tcp_header); + debug_print(WARNING, "UDP response!"); + + /* Short-circuit DNS */ + if (ntohs(udp->source_port) == 53) { + debug_print(WARNING, "UDP response to DNS query!"); + parse_dns_response(debug_file, udp); + return; + } + + if (ntohs(udp->source_port) == 67) { + debug_print(WARNING, "UDP response to DHCP!"); + + { + void * tmp = malloc(1024); + size_t packet_size = write_arp_request(tmp, _netif.gateway); + _netif.send_packet(tmp, packet_size); + free(tmp); + } + + return; + } + + /* Find socket */ + if (hashmap_has(_udp_sockets, (void *)ntohs(udp->source_port))) { + /* Do the thing */ + + } else { + /* ??? */ + } + +} + +static void net_handle_ipv4(struct ipv4_packet * ipv4) { + debug_print(INFO, "net_handle_ipv4: ENTER"); + switch (ipv4->protocol) { + case IPV4_PROT_TCP: + net_handle_tcp((struct tcp_header *)ipv4->payload, ntohs(ipv4->length) - sizeof(struct ipv4_packet)); + break; + case IPV4_PROT_UDP: + net_handle_udp((struct udp_packet *)ipv4->payload, ntohs(ipv4->length) - sizeof(struct ipv4_packet)); + break; + default: + /* XXX */ + break; + } +} + +static struct ethernet_packet* net_receive(void) { + struct ethernet_packet *eth = _netif.get_packet(); + + return eth; +} + +int net_connect(struct socket* socket, uint32_t dest_ip, uint16_t dest_port) { + if (socket->sock_type == SOCK_DGRAM) { + // Can't connect UDP + return -1; + } + + memset(socket->mac, 0, sizeof(socket->mac)); // idk + socket->port_recv = next_ephemeral_port(); + socket->proto_sock.tcp_socket.is_connected = list_create(); + socket->proto_sock.tcp_socket.seq_no = 0; + socket->proto_sock.tcp_socket.ack_no = 0; + socket->proto_sock.tcp_socket.status = 0; + + socket->packet_queue = list_create(); + socket->packet_wait = list_create(); + socket->alert_waiters = list_create(); + + socket->ip = dest_ip; //ip_aton("10.255.50.206"); + socket->port_dest = dest_port; //12345; + + debug_print(WARNING, "net_connect: using ephemeral port: %d", (void*)socket->port_recv); + + hashmap_set(_tcp_sockets, (void*)socket->port_recv, socket); + + net_send_tcp(socket, TCP_FLAGS_SYN, NULL, 0); + // debug_print(WARNING, "net_connect:sent tcp SYN: %d", ret); + + // Race condition here - if net_handle_tcp runs and connects before this sleep + sleep_on(socket->proto_sock.tcp_socket.is_connected); + + return 1; +} + +static void placeholder_dhcp(void) { + debug_print(NOTICE, "Sending DHCP discover"); + void * tmp = malloc(1024); + size_t packet_size = write_dhcp_packet(tmp); + _netif.send_packet(tmp, packet_size); + free(tmp); + + while (1) { + struct ethernet_packet * eth = (struct ethernet_packet *)_netif.get_packet(); + uint16_t eth_type = ntohs(eth->type); + + debug_print(NOTICE, "Ethernet II, Src: (%2x:%2x:%2x:%2x:%2x:%2x), Dst: (%2x:%2x:%2x:%2x:%2x:%2x) [type=%4x])", + eth->source[0], eth->source[1], eth->source[2], + eth->source[3], eth->source[4], eth->source[5], + eth->destination[0], eth->destination[1], eth->destination[2], + eth->destination[3], eth->destination[4], eth->destination[5], + eth_type); + + if (eth_type != 0x0800) { + debug_print(WARNING, "ARP packet while waiting for DHCP..."); + free(eth); + continue; + } + + + struct ipv4_packet * ipv4 = (struct ipv4_packet *)eth->payload; + uint32_t src_addr = ntohl(ipv4->source); + uint32_t dst_addr = ntohl(ipv4->destination); + uint16_t length = ntohs(ipv4->length); + + char src_ip[16]; + char dst_ip[16]; + + ip_ntoa(src_addr, src_ip); + ip_ntoa(dst_addr, dst_ip); + + debug_print(NOTICE, "IP packet [%s → %s] length=%d bytes", + src_ip, dst_ip, length); + + if (ipv4->protocol != IPV4_PROT_UDP) { + debug_print(WARNING, "Protocol: %d", ipv4->protocol); + debug_print(WARNING, "Bad packet..."); + free(eth); + continue; + } + + struct udp_packet * udp = (struct udp_packet *)ipv4->payload;; + uint16_t src_port = ntohs(udp->source_port); + uint16_t dst_port = ntohs(udp->destination_port); + uint16_t udp_len = ntohs(udp->length); + + debug_print(NOTICE, "UDP [%d → %d] length=%d bytes", + src_port, dst_port, udp_len); + + if (dst_port != 68) { + debug_print(WARNING, "Destination port: %d", dst_port); + debug_print(WARNING, "Bad packet..."); + free(eth); + continue; + } + + struct dhcp_packet * dhcp = (struct dhcp_packet *)udp->payload; + uint32_t yiaddr = ntohl(dhcp->yiaddr); + + char yiaddr_ip[16]; + ip_ntoa(yiaddr, yiaddr_ip); + debug_print(NOTICE, "DHCP Offer: %s", yiaddr_ip); + + _netif.source = yiaddr; + + debug_print(NOTICE," Scanning offer for DNS servers..."); + + size_t i = sizeof(struct dhcp_packet); + size_t j = 0; + while (i < length) { + uint8_t type = dhcp->options[j]; + uint8_t len = dhcp->options[j+1]; + uint8_t * data = &dhcp->options[j+2]; + + debug_print(NOTICE," type=%d, len=%d", type, len); + if (type == 255) { + break; + } else if (type == 6) { + /* DNS Server! */ + uint32_t dnsaddr = ntohl(*(uint32_t *)data); + char ip[16]; + ip_ntoa(dnsaddr, ip); + debug_print(NOTICE, "Found one: %s", ip); + _dns_server = dnsaddr; + } else if (type == 3) { + _netif.gateway = ntohl(*(uint32_t *)data); + } + + j += 2 + len; + i += 2 + len; + } + + debug_print(NOTICE, "Sending DHCP Request..."); + void * tmp = malloc(1024); + size_t packet_size = write_dhcp_request(tmp, (uint8_t *)&dhcp->yiaddr); + _netif.send_packet(tmp, packet_size); + free(tmp); + + free(eth); + + break; + } + +} + +struct arp { + uint16_t htype; + uint16_t proto; + + uint8_t hlen; + uint8_t plen; + + uint16_t oper; + + uint8_t sender_ha[6]; + uint32_t sender_ip; + uint8_t target_ha[6]; + uint32_t target_ip; + + uint8_t padding[18]; +} __attribute__((packed)); + +static size_t write_arp_response(uint8_t * buffer, struct arp * source) { + size_t offset = 0; + + /* Then, let's write an ethernet frame */ + struct ethernet_packet eth_out = { + .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], + _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, + .destination = BROADCAST_MAC, + .type = htons(0x0806), + }; + + memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); + offset += sizeof(struct ethernet_packet); + + struct arp arp_out; + + arp_out.htype = source->htype; + arp_out.proto = source->proto; + + arp_out.hlen = 6; + arp_out.plen = 4; + arp_out.oper = ntohs(2); + + arp_out.sender_ha[0] = _netif.hwaddr[0]; + arp_out.sender_ha[1] = _netif.hwaddr[1]; + arp_out.sender_ha[2] = _netif.hwaddr[2]; + arp_out.sender_ha[3] = _netif.hwaddr[3]; + arp_out.sender_ha[4] = _netif.hwaddr[4]; + arp_out.sender_ha[5] = _netif.hwaddr[5]; + arp_out.sender_ip = ntohl(_netif.source); + + arp_out.target_ha[0] = source->sender_ha[0]; + arp_out.target_ha[1] = source->sender_ha[1]; + arp_out.target_ha[2] = source->sender_ha[2]; + arp_out.target_ha[3] = source->sender_ha[3]; + arp_out.target_ha[4] = source->sender_ha[4]; + arp_out.target_ha[5] = source->sender_ha[5]; + + arp_out.target_ip = source->sender_ip; + + memcpy(&buffer[offset], &arp_out, sizeof(struct arp)); + offset += sizeof(struct arp); + + return offset; +} + +static size_t write_arp_request(uint8_t * buffer, uint32_t ip) { + size_t offset = 0; + + debug_print(WARNING, "Request ARP from gateway address %x", ip); + + /* Then, let's write an ethernet frame */ + struct ethernet_packet eth_out = { + .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], + _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, + .destination = BROADCAST_MAC, + .type = htons(0x0806), + }; + + memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); + offset += sizeof(struct ethernet_packet); + + struct arp arp_out; + + arp_out.htype = ntohs(1); + + debug_print(WARNING, "Request ARP from gateway address %x", ip); + arp_out.proto = ntohs(0x0800); + + arp_out.hlen = 6; + arp_out.plen = 4; + arp_out.oper = ntohs(1); + + arp_out.sender_ha[0] = _netif.hwaddr[0]; + arp_out.sender_ha[1] = _netif.hwaddr[1]; + arp_out.sender_ha[2] = _netif.hwaddr[2]; + arp_out.sender_ha[3] = _netif.hwaddr[3]; + arp_out.sender_ha[4] = _netif.hwaddr[4]; + arp_out.sender_ha[5] = _netif.hwaddr[5]; + arp_out.sender_ip = ntohl(_netif.source); + + arp_out.target_ha[0] = 0; + arp_out.target_ha[1] = 0; + arp_out.target_ha[2] = 0; + arp_out.target_ha[3] = 0; + arp_out.target_ha[4] = 0; + arp_out.target_ha[5] = 0; + + arp_out.target_ip = ntohl(ip); + + memcpy(&buffer[offset], &arp_out, sizeof(struct arp)); + offset += sizeof(struct arp); + + return offset; +} + + +static void net_handle_arp(struct ethernet_packet * eth) { + debug_print(WARNING, "ARP packet..."); + + struct arp * arp = (struct arp *)ð->payload; + + char sender_ip[16]; + char target_ip[16]; + + ip_ntoa(ntohl(arp->sender_ip), sender_ip); + ip_ntoa(ntohl(arp->target_ip), target_ip); + + debug_print(WARNING, "%2x:%2x:%2x:%2x:%2x:%2x (%s) → %2x:%2x:%2x:%2x:%2x:%2x (%s) is", + arp->sender_ha[0], + arp->sender_ha[1], + arp->sender_ha[2], + arp->sender_ha[3], + arp->sender_ha[4], + arp->sender_ha[5], + sender_ip, + arp->target_ha[0], + arp->target_ha[1], + arp->target_ha[2], + arp->target_ha[3], + arp->target_ha[4], + arp->target_ha[5], + target_ip); + + if (ntohs(arp->oper) == 1) { + + if (ntohl(arp->target_ip) == _netif.source) { + debug_print(WARNING, "That's us!"); + + { + void * tmp = malloc(1024); + size_t packet_size = write_arp_response(tmp, arp); + _netif.send_packet(tmp, packet_size); + free(tmp); + } + + } + + } else { + if (ntohl(arp->target_ip) == _netif.source) { + debug_print(WARNING, "It's a response to our query!"); + if (ntohl(arp->sender_ip) == _netif.gateway) { + _gateway[0] = arp->sender_ha[0]; + _gateway[1] = arp->sender_ha[1]; + _gateway[2] = arp->sender_ha[2]; + _gateway[3] = arp->sender_ha[3]; + _gateway[4] = arp->sender_ha[4]; + _gateway[5] = arp->sender_ha[5]; + } + } else { + debug_print(WARNING, "Response to someone else...\n"); + } + } + +} + +void net_handler(void * data, char * name) { + /* Network Packet Handler*/ + _netif.extra = NULL; + + _dns_server = ip_aton("10.0.2.3"); + + placeholder_dhcp(); + + dns_waiters = list_create(); + + _tcp_sockets = hashmap_create_int(0xFF); + _udp_sockets = hashmap_create_int(0xFF); + + while (1) { + struct ethernet_packet * eth = net_receive(); + + if (!eth) continue; + + switch (ntohs(eth->type)) { + case ETHERNET_TYPE_IPV4: + net_handle_ipv4((struct ipv4_packet *)eth->payload); + break; + case ETHERNET_TYPE_ARP: + net_handle_arp(eth); + break; + } + + free(eth); + } +} + +size_t write_dhcp_packet(uint8_t * buffer) { + size_t offset = 0; + size_t payload_size = sizeof(struct dhcp_packet); + + /* First, let's figure out how big this is supposed to be... */ + + uint8_t dhcp_options[] = { + 53, /* Message type */ + 1, /* Length: 1 */ + 1, /* Discover */ + 55, + 2, + 3, + 6, + 255, /* END */ + }; + + payload_size += sizeof(dhcp_options); + + /* Then, let's write an ethernet frame */ + struct ethernet_packet eth_out = { + .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], + _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, + .destination = BROADCAST_MAC, + .type = htons(0x0800), + }; + + memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); + offset += sizeof(struct ethernet_packet); + + /* Prepare the IPv4 header */ + uint16_t _length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + payload_size); + uint16_t _ident = htons(1); + + struct ipv4_packet ipv4_out = { + .version_ihl = ((0x4 << 4) | (0x5 << 0)), /* 4 = ipv4, 5 = no options */ + .dscp_ecn = 0, /* not setting either of those */ + .length = _length, + .ident = _ident, + .flags_fragment = 0, + .ttl = 0x40, + .protocol = IPV4_PROT_UDP, + .checksum = 0, /* fill this in later */ + .source = htonl(ip_aton("0.0.0.0")), + .destination = htonl(ip_aton("255.255.255.255")), + }; + + uint16_t checksum = calculate_ipv4_checksum(&ipv4_out); + ipv4_out.checksum = htons(checksum); + + memcpy(&buffer[offset], &ipv4_out, sizeof(struct ipv4_packet)); + offset += sizeof(struct ipv4_packet); + + uint16_t _udp_source = htons(68); + uint16_t _udp_destination = htons(67); + uint16_t _udp_length = htons(sizeof(struct udp_packet) + payload_size); + + /* Now let's build a UDP packet */ + struct udp_packet udp_out = { + .source_port = _udp_source, + .destination_port = _udp_destination, + .length = _udp_length, + .checksum = 0, + }; + + /* XXX calculate checksum here */ + + memcpy(&buffer[offset], &udp_out, sizeof(struct udp_packet)); + offset += sizeof(struct udp_packet); + + /* BOOTP headers */ + struct dhcp_packet bootp_out = { + .op = 1, + .htype = 1, + .hlen = 6, /* mac address... */ + .hops = 0, + .xid = htonl(0x1337), /* transaction id */ + .secs = 0, + .flags = 0, + + .ciaddr = 0x000000, + .yiaddr = 0x000000, + .siaddr = 0x000000, + .giaddr = 0x000000, + + .chaddr = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], + _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, + .sname = {0}, + .file = {0}, + .magic = htonl(DHCP_MAGIC), + }; + + memcpy(&buffer[offset], &bootp_out, sizeof(struct dhcp_packet)); + offset += sizeof(struct dhcp_packet); + + memcpy(&buffer[offset], &dhcp_options, sizeof(dhcp_options)); + offset += sizeof(dhcp_options); + + return offset; +} + +size_t write_dhcp_request(uint8_t * buffer, uint8_t * ip) { + size_t offset = 0; + size_t payload_size = sizeof(struct dhcp_packet); + + /* First, let's figure out how big this is supposed to be... */ + + uint8_t dhcp_options[] = { + 53, /* Message type */ + 1, /* Length: 1 */ + 3, /* Request */ + 50, + 4, /* requested ip */ + ip[0],ip[1],ip[2],ip[3], + 55, + 2, + 3, + 6, + 255, /* END */ + }; + + payload_size += sizeof(dhcp_options); + + /* Then, let's write an ethernet frame */ + struct ethernet_packet eth_out = { + .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], + _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, + .destination = BROADCAST_MAC, + .type = htons(0x0800), + }; + + memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet)); + offset += sizeof(struct ethernet_packet); + + /* Prepare the IPv4 header */ + uint16_t _length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + payload_size); + uint16_t _ident = htons(1); + + struct ipv4_packet ipv4_out = { + .version_ihl = ((0x4 << 4) | (0x5 << 0)), /* 4 = ipv4, 5 = no options */ + .dscp_ecn = 0, /* not setting either of those */ + .length = _length, + .ident = _ident, + .flags_fragment = 0, + .ttl = 0x40, + .protocol = IPV4_PROT_UDP, + .checksum = 0, /* fill this in later */ + .source = htonl(ip_aton("0.0.0.0")), + .destination = htonl(ip_aton("255.255.255.255")), + }; + + uint16_t checksum = calculate_ipv4_checksum(&ipv4_out); + ipv4_out.checksum = htons(checksum); + + memcpy(&buffer[offset], &ipv4_out, sizeof(struct ipv4_packet)); + offset += sizeof(struct ipv4_packet); + + uint16_t _udp_source = htons(68); + uint16_t _udp_destination = htons(67); + uint16_t _udp_length = htons(sizeof(struct udp_packet) + payload_size); + + /* Now let's build a UDP packet */ + struct udp_packet udp_out = { + .source_port = _udp_source, + .destination_port = _udp_destination, + .length = _udp_length, + .checksum = 0, + }; + + /* XXX calculate checksum here */ + + memcpy(&buffer[offset], &udp_out, sizeof(struct udp_packet)); + offset += sizeof(struct udp_packet); + + /* BOOTP headers */ + struct dhcp_packet bootp_out = { + .op = 1, + .htype = 1, + .hlen = 6, /* mac address... */ + .hops = 0, + .xid = htonl(0x1337), /* transaction id */ + .secs = 0, + .flags = 0, + + .ciaddr = 0x000000, + .yiaddr = 0x000000, + .siaddr = 0x000000, + .giaddr = 0x000000, + + .chaddr = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2], + _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] }, + .sname = {0}, + .file = {0}, + .magic = htonl(DHCP_MAGIC), + }; + + memcpy(&buffer[offset], &bootp_out, sizeof(struct dhcp_packet)); + offset += sizeof(struct dhcp_packet); + + memcpy(&buffer[offset], &dhcp_options, sizeof(dhcp_options)); + offset += sizeof(dhcp_options); + + return offset; +} + + +static void parse_dns_response(fs_node_t * tty, void * last_packet) { + struct udp_packet * udp = (struct udp_packet *)last_packet; + uint16_t src_port = ntohs(udp->source_port); + uint16_t dst_port = ntohs(udp->destination_port); + uint16_t udp_len = ntohs(udp->length); + + fprintf(tty, "UDP [%d → %d] length=%d bytes\n", + src_port, dst_port, udp_len); + + struct dns_packet * dns = (struct dns_packet *)udp->payload; + uint16_t dns_questions = ntohs(dns->questions); + uint16_t dns_answers = ntohs(dns->answers); + fprintf(tty, "DNS - %d queries, %d answers\n", + dns_questions, dns_answers); + + fprintf(tty, "Queries:\n"); + int offset = sizeof(struct dns_packet); + int queries = 0; + uint8_t * bytes = (uint8_t *)dns; + while (queries < dns_questions) { + offset = print_dns_name(tty, dns, offset); + uint16_t * d = (uint16_t *)&bytes[offset]; + fprintf(tty, " - Type: %4x %4x\n", ntohs(d[0]), ntohs(d[1])); + offset += 4; + queries++; + } + + fprintf(tty, "Answers:\n"); + int answers = 0; + while (answers < dns_answers) { + char buf[1024]; + size_t ret = dns_name_to_normal_name(dns, offset, buf); + debug_print(WARNING, "%d - %s", ret, buf); + offset = print_dns_name(tty, dns, offset); + uint16_t * d = (uint16_t *)&bytes[offset]; + fprintf(tty, " - Type: %4x %4x; ", ntohs(d[0]), ntohs(d[1])); + offset += 4; + uint32_t * t = (uint32_t *)&bytes[offset]; + fprintf(tty, "TTL: %d; ", ntohl(t[0])); + offset += 4; + uint16_t * l = (uint16_t *)&bytes[offset]; + int _l = ntohs(l[0]); + fprintf(tty, "len: %d; ", _l); + offset += 2; + if (_l == 4) { + uint32_t * i = (uint32_t *)&bytes[offset]; + char ip[16]; + ip_ntoa(ntohl(i[0]), ip); + fprintf(tty, " Address: %s\n", ip); + debug_print(NOTICE, "Domain [%s] maps to [%s]", buf, ip); + if (!hashmap_has(dns_cache, buf)) { + hashmap_set(dns_cache, buf, strdup(ip)); + } + } else { + if (ntohs(d[0]) == 5) { + fprintf(tty, "CNAME: "); + char buffer[256]; + get_dns_name(buffer, dns, offset); + fprintf(tty, "%s\n", buffer); + if (strlen(buffer)) { + buffer[strlen(buffer)-1] = '\0'; + } + uint32_t addr; + if (gethost(buffer,&addr) == 2) { + debug_print(WARNING,"Can't provide a response yet, but going to query again in a moment."); + } else { + if (!hashmap_has(dns_cache, buf)) { + char ip[16]; + ip_ntoa(addr, ip); + hashmap_set(dns_cache, buf, strdup(ip)); + fprintf(tty, "resolves to %s\n", ip); + } + } + } else { + fprintf(tty, "dunno\n"); + } + } + offset += _l; + answers++; + } + + wakeup_queue(dns_waiters); +} + +static fs_node_t * netfs_create(void) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, "net"); + fnode->mask = 0555; + fnode->flags = FS_DIRECTORY; + fnode->readdir = readdir_netfs; + fnode->finddir = finddir_netfs; + fnode->ioctl = ioctl_netfs; + fnode->nlink = 1; + return fnode; +} + +static int init(void) { + dns_cache = hashmap_create(10); + + hashmap_set(dns_cache, "dakko.us", strdup("104.131.140.26")); + hashmap_set(dns_cache, "toaruos.org", strdup("104.131.140.26")); + hashmap_set(dns_cache, "www.toaruos.org", strdup("104.131.140.26")); + hashmap_set(dns_cache, "www.yelp.com", strdup("104.16.57.23")); + hashmap_set(dns_cache, "s3-media2.fl.yelpcdn.com", strdup("199.27.79.175")); + hashmap_set(dns_cache, "forum.osdev.org", strdup("173.255.206.39")); + hashmap_set(dns_cache, "wolfgun.puckipedia.com", strdup("104.47.147.203")); + hashmap_set(dns_cache, "irc.freenode.net", strdup("91.217.189.42")); + hashmap_set(dns_cache, "i.imgur.com", strdup("23.235.47.193")); + + /* /dev/net/{domain|ip}/{protocol}/{port} */ + vfs_mount("/dev/net", netfs_create()); + + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(net, init, fini); diff --git a/modules/packetfs.c b/modules/packetfs.c new file mode 100644 index 00000000..86ed8215 --- /dev/null +++ b/modules/packetfs.c @@ -0,0 +1,480 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include +#include + +#define MAX_PACKET_SIZE 1024 + +typedef struct packet_manager { + /* uh, nothing, lol */ + list_t * exchanges; + spin_lock_t lock; +} pex_t; + +typedef struct packet_exchange { + char * name; + char fresh; + spin_lock_t lock; + fs_node_t * server_pipe; + list_t * clients; +} pex_ex_t; + +typedef struct packet_client { + pex_ex_t * parent; + fs_node_t * pipe; +} pex_client_t; + + +typedef struct packet { + pex_client_t * source; + size_t size; + uint8_t data[]; +} packet_t; + +typedef struct server_write_header { + pex_client_t * target; + uint8_t data[]; +} header_t; + +static void receive_packet(fs_node_t * socket, packet_t ** out) { + packet_t tmp; + read_fs(socket, 0, sizeof(struct packet), (uint8_t *)&tmp); + *out = malloc(tmp.size + sizeof(struct packet)); + memcpy(*out, &tmp, sizeof(struct packet)); + + if (tmp.size) { + read_fs(socket, 0, tmp.size, (uint8_t *)(*out)->data); + } +} + +static void send_to_server(pex_ex_t * p, pex_client_t * c, size_t size, void * data) { + size_t p_size = size + sizeof(struct packet); + packet_t * packet = malloc(p_size); + + packet->source = c; + packet->size = size; + + if (size) { + memcpy(packet->data, data, size); + } + + write_fs(p->server_pipe, 0, p_size, (uint8_t *)packet); + + free(packet); +} + +static int send_to_client(pex_ex_t * p, pex_client_t * c, size_t size, void * data) { + size_t p_size = size + sizeof(struct packet); + + /* Verify there is space on the client */ + if (pipe_unsize(c->pipe) < (int)p_size) { + return -1; + } + + packet_t * packet = malloc(p_size); + + memcpy(packet->data, data, size); + packet->source = NULL; + packet->size = size; + + write_fs(c->pipe, 0, p_size, (uint8_t *)packet); + + free(packet); + return size; +} + +static pex_client_t * create_client(pex_ex_t * p) { + pex_client_t * out = malloc(sizeof(pex_client_t)); + out->parent = p; + out->pipe = make_pipe(4096); + return out; +} + +static uint32_t read_server(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) { + pex_ex_t * p = (pex_ex_t *)node->device; + debug_print(INFO, "[pex] server read(...)"); + + packet_t * packet; + + receive_packet(p->server_pipe, &packet); + + debug_print(INFO, "Server recevied packet of size %d, was waiting for at most %d", packet->size, size); + + if (packet->size + sizeof(packet_t) > size) { + return -1; + } + + memcpy(buffer, packet, packet->size + sizeof(packet_t)); + uint32_t out = packet->size + sizeof(packet_t); + + free(packet); + return out; +} + +static uint32_t write_server(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) { + pex_ex_t * p = (pex_ex_t *)node->device; + debug_print(INFO, "[pex] server write(...)"); + + header_t * head = (header_t *)buffer; + + if (size - sizeof(header_t) > MAX_PACKET_SIZE) { + return -1; + } + + if (head->target == NULL) { + /* Brodcast packet */ + spin_lock(p->lock); + foreach(f, p->clients) { + debug_print(INFO, "Sending to client 0x%x", f->value); + send_to_client(p, (pex_client_t *)f->value, size - sizeof(header_t), head->data); + } + spin_unlock(p->lock); + debug_print(INFO, "Done broadcasting to clients."); + return size; + } else if (head->target->parent != p) { + debug_print(WARNING, "[pex] Invalid packet from server? (pid=%d)", current_process->id); + return -1; + } + + return send_to_client(p, head->target, size - sizeof(header_t), head->data); +} + +static int ioctl_server(fs_node_t * node, int request, void * argp) { + pex_ex_t * p = (pex_ex_t *)node->device; + + switch (request) { + case IOCTL_PACKETFS_QUEUED: + return pipe_size(p->server_pipe); + default: + return -1; + } +} + +static uint32_t read_client(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) { + pex_client_t * c = (pex_client_t *)node->inode; + if (c->parent != node->device) { + debug_print(WARNING, "[pex] Invalid device endpoint on client read?"); + return -1; + } + + debug_print(INFO, "[pex] client read(...)"); + + packet_t * packet; + + receive_packet(c->pipe, &packet); + + if (packet->size > size) { + debug_print(WARNING, "[pex] Client is not reading enough bytes to hold packet of size %d", packet->size); + return -1; + } + + memcpy(buffer, &packet->data, packet->size); + uint32_t out = packet->size; + + debug_print(INFO, "[pex] Client received packet of size %d", packet->size); + + free(packet); + return out; +} + +static uint32_t write_client(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) { + pex_client_t * c = (pex_client_t *)node->inode; + if (c->parent != node->device) { + debug_print(WARNING, "[pex] Invalid device endpoint on client write?"); + return -1; + } + + debug_print(INFO, "[pex] client write(...)"); + + if (size > MAX_PACKET_SIZE) { + debug_print(WARNING, "Size of %d is too big.", size); + return -1; + } + + debug_print(INFO, "Sending packet of size %d to parent", size); + send_to_server(c->parent, c, size, buffer); + + return size; +} + +static int ioctl_client(fs_node_t * node, int request, void * argp) { + pex_client_t * c = (pex_client_t *)node->inode; + + switch (request) { + case IOCTL_PACKETFS_QUEUED: + return pipe_size(c->pipe); + default: + return -1; + } +} + +static void close_client(fs_node_t * node) { + pex_client_t * c = (pex_client_t *)node->inode; + pex_ex_t * p = c->parent; + + debug_print(WARNING, "Closing packetfs client: 0x%x:0x%x", p, c); + + spin_lock(p->lock); + + node_t * n = list_find(p->clients, c); + if (n && n->owner == p->clients) { + list_delete(p->clients, n); + free(n); + } + + spin_unlock(p->lock); + + char tmp[1]; + + send_to_server(p, c, 0, tmp); + + free(c); +} + +static int wait_server(fs_node_t * node, void * process) { + pex_ex_t * p = (pex_ex_t *)node->device; + return selectwait_fs(p->server_pipe, process); +} +static int check_server(fs_node_t * node) { + pex_ex_t * p = (pex_ex_t *)node->device; + return selectcheck_fs(p->server_pipe); +} + +static int wait_client(fs_node_t * node, void * process) { + pex_client_t * c = (pex_client_t *)node->inode; + return selectwait_fs(c->pipe, process); +} +static int check_client(fs_node_t * node) { + pex_client_t * c = (pex_client_t *)node->inode; + return selectcheck_fs(c->pipe); +} + +static void open_pex(fs_node_t * node, unsigned int flags) { + pex_ex_t * t = (pex_ex_t *)(node->device); + + debug_print(NOTICE, "Opening packet exchange %s with flags 0x%x", t->name, flags); + + if (flags & O_CREAT && t->fresh) { + t->fresh = 0; + node->inode = 0; + /* Set up the server side */ + node->read = read_server; + node->write = write_server; + node->ioctl = ioctl_server; + node->selectcheck = check_server; + node->selectwait = wait_server; + debug_print(INFO, "[pex] Server launched: %s", t->name); + debug_print(INFO, "fs_node = 0x%x", node); + } else if (!(flags & O_CREAT)) { + pex_client_t * client = create_client(t); + node->inode = (uintptr_t)client; + + node->read = read_client; + node->write = write_client; + node->ioctl = ioctl_client; + node->close = close_client; + + node->selectcheck = check_client; + node->selectwait = wait_client; + + list_insert(t->clients, client); + + /* XXX: Send plumbing message to server for new client connection */ + debug_print(INFO, "[pex] Client connected: %s:0%x", t->name, node->inode); + } else if (flags & O_CREAT && !t->fresh) { + /* XXX: You dun goofed */ + } + + return; +} + +static struct dirent * readdir_packetfs(fs_node_t *node, uint32_t index) { + pex_t * p = (pex_t *)node->device; + unsigned int i = 0; + + debug_print(INFO, "[pex] readdir(%d)", index); + + if (index == 0) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, "."); + return out; + } + + if (index == 1) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, ".."); + return out; + } + + index -= 2; + + if (index >= p->exchanges->length) { + return NULL; + } + + spin_lock(p->lock); + + foreach(f, p->exchanges) { + if (i == index) { + spin_unlock(p->lock); + pex_ex_t * t = (pex_ex_t *)f->value; + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = (uint32_t)t; + strcpy(out->name, t->name); + return out; + } else { + ++i; + } + } + + spin_unlock(p->lock); + + return NULL; +} + +static fs_node_t * file_from_pex(pex_ex_t * pex) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, pex->name); + fnode->device = pex; + fnode->mask = 0666; + fnode->flags = FS_CHARDEVICE; + fnode->open = open_pex; + fnode->read = read_server; + fnode->write = write_server; + return fnode; +} + +static fs_node_t * finddir_packetfs(fs_node_t * node, char * name) { + if (!name) return NULL; + pex_t * p = (pex_t *)node->device; + + debug_print(INFO, "[pex] finddir(%s)", name); + + spin_lock(p->lock); + + foreach(f, p->exchanges) { + pex_ex_t * t = (pex_ex_t *)f->value; + if (!strcmp(name, t->name)) { + spin_unlock(p->lock); + return file_from_pex(t); + } + } + + spin_unlock(p->lock); + + return NULL; +} + +static void create_packetfs(fs_node_t *parent, char *name, uint16_t permission) { + if (!name) return; + + pex_t * p = (pex_t *)parent->device; + + debug_print(NOTICE, "[pex] create(%s)", name); + + spin_lock(p->lock); + + foreach(f, p->exchanges) { + pex_ex_t * t = (pex_ex_t *)f->value; + if (!strcmp(name, t->name)) { + spin_unlock(p->lock); + /* Already exists */ + return; + } + } + + /* Make it */ + pex_ex_t * new_exchange = malloc(sizeof(pex_ex_t)); + + new_exchange->name = strdup(name); + new_exchange->fresh = 1; + new_exchange->clients = list_create(); + new_exchange->server_pipe = make_pipe(4096); + + spin_init(new_exchange->lock); + /* XXX Create exchange server pipe */ + + list_insert(p->exchanges, new_exchange); + + spin_unlock(p->lock); + +} + +static void destroy_pex(pex_ex_t * p) { + /* XXX */ +} + +static void unlink_packetfs(fs_node_t *parent, char *name) { + if (!name) return; + + pex_t * p = (pex_t *)parent->device; + + debug_print(NOTICE, "[pex] unlink(%s)", name); + + int i = -1, j = 0; + + spin_lock(p->lock); + + foreach(f, p->exchanges) { + pex_ex_t * t = (pex_ex_t *)f->value; + if (!strcmp(name, t->name)) { + destroy_pex(t); + i = j; + break; + } + j++; + } + + if (i >= 0) { + list_remove(p->exchanges, i); + } + + spin_unlock(p->lock); +} + +static fs_node_t * packetfs_manager(void) { + pex_t * pex = malloc(sizeof(pex_t)); + pex->exchanges = list_create(); + + spin_init(pex->lock); + + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, "pex"); + fnode->device = pex; + fnode->mask = 0777; + fnode->flags = FS_DIRECTORY; + fnode->readdir = readdir_packetfs; + fnode->finddir = finddir_packetfs; + fnode->create = create_packetfs; + fnode->unlink = unlink_packetfs; + + return fnode; +} + +static int init(void) { + fs_node_t * packet_mgr = packetfs_manager(); + vfs_mount("/dev/pex", packet_mgr); + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(packetfs, init, fini); diff --git a/modules/pcnet.c b/modules/pcnet.c new file mode 100644 index 00000000..86734625 --- /dev/null +++ b/modules/pcnet.c @@ -0,0 +1,374 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016 Kevin Lange + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static list_t * net_queue = NULL; +static spin_lock_t net_queue_lock = { 0 }; +static list_t * rx_wait; + +static uint32_t pcnet_device_pci = 0x00000000; +static uint32_t pcnet_io_base = 0; +static uint32_t pcnet_mem_base = 0; +static int pcnet_irq; +static uint8_t mac[6]; + +static uint32_t pcnet_buffer_phys; +static uint8_t *pcnet_buffer_virt; + +static uint8_t * pcnet_rx_de_start; +static uint8_t * pcnet_tx_de_start; +static uint8_t * pcnet_rx_start; +static uint8_t * pcnet_tx_start; + +static uint32_t pcnet_rx_de_phys; +static uint32_t pcnet_tx_de_phys; +static uint32_t pcnet_rx_phys; +static uint32_t pcnet_tx_phys; + +static int pcnet_rx_buffer_id = 0; +static int pcnet_tx_buffer_id = 0; + +#define PCNET_DE_SIZE 16 +#define PCNET_BUFFER_SIZE 1548 +#define PCNET_RX_COUNT 32 +#define PCNET_TX_COUNT 8 + +static void find_pcnet(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + if ((vendorid == 0x1022) && (deviceid == 0x2000)) { + *((uint32_t *)extra) = device; + } +} + +static void write_rap32(uint32_t value) { + outportl(pcnet_io_base + 0x14, value); +} +static void write_rap16(uint16_t value) { + outports(pcnet_io_base + 0x12, value); +} +static uint32_t read_csr32(uint32_t csr_no) { + write_rap32(csr_no); + return inportl(pcnet_io_base + 0x10); +} +static uint16_t read_csr16(uint16_t csr_no) { + write_rap32(csr_no); + return inports(pcnet_io_base + 0x10); +} +static void write_csr32(uint32_t csr_no, uint32_t value) { + write_rap32(csr_no); + outportl(pcnet_io_base + 0x10, value); +} +static void write_csr16(uint32_t csr_no, uint16_t value) { + write_rap16(csr_no); + outports(pcnet_io_base + 0x10, value); +} +static uint32_t read_bcr32(uint32_t bcr_no) { + write_rap32(bcr_no); + return inportl(pcnet_io_base + 0x1c); +} +static void write_bcr32(uint32_t bcr_no, uint32_t value) { + write_rap32(bcr_no); + outportl(pcnet_io_base + 0x1c, value); +} + +static uint32_t virt_to_phys(uint8_t * virt) { + return ((uintptr_t)virt - (uintptr_t)pcnet_buffer_virt) + pcnet_buffer_phys; +} + +static int driver_owns(uint8_t * de_table, int index) { + return (de_table[PCNET_DE_SIZE * index + 7] & 0x80) == 0; +} + +static int next_tx_index(int current_tx_index) { + int out = current_tx_index + 1; + if (out == PCNET_TX_COUNT) { + return 0; + } + return out; +} + +static int next_rx_index(int current_rx_index) { + int out = current_rx_index + 1; + if (out == PCNET_RX_COUNT) { + return 0; + } + return out; +} + +static void init_descriptor(int index, int is_tx) { + uint8_t * de_table = is_tx ? pcnet_tx_de_start : pcnet_rx_de_start; + + memset(&de_table[index * PCNET_DE_SIZE], 0, PCNET_DE_SIZE); + + uint32_t buf_addr = is_tx ? pcnet_tx_phys : pcnet_rx_phys; + *(uint32_t *)&de_table[index * PCNET_DE_SIZE] = buf_addr + index * PCNET_BUFFER_SIZE; + + uint16_t bcnt = (uint16_t)(-PCNET_BUFFER_SIZE); + bcnt &= 0x0FFF; + bcnt |= 0xF000; + *(uint16_t *)&de_table[index * PCNET_DE_SIZE + 4] = bcnt; + + if (!is_tx) { + de_table[index * PCNET_DE_SIZE + 7] = 0x80; + } +} + +static void enqueue_packet(void * buffer) { + spin_lock(net_queue_lock); + list_insert(net_queue, buffer); + spin_unlock(net_queue_lock); +} + +static struct ethernet_packet * dequeue_packet(void) { + while (!net_queue->length) { + sleep_on(rx_wait); + } + + spin_lock(net_queue_lock); + node_t * n = list_dequeue(net_queue); + void* value = n->value; + free(n); + spin_unlock(net_queue_lock); + + return value; +} + +static uint8_t* pcnet_get_mac() { + return mac; +} + +static void pcnet_send_packet(uint8_t* payload, size_t payload_size) { + if (!driver_owns(pcnet_tx_de_start, pcnet_tx_buffer_id)) { + /* sleep? */ + debug_print(ERROR, "No transmit descriptors available. Bailing."); + return; + } + if (payload_size > PCNET_BUFFER_SIZE) { + debug_print(ERROR, "Packet too big; max is %d, got %d", PCNET_BUFFER_SIZE, payload_size); + return; + } + memcpy((void *)(pcnet_tx_start + pcnet_tx_buffer_id * PCNET_BUFFER_SIZE), payload, payload_size); + + pcnet_tx_de_start[pcnet_tx_buffer_id * PCNET_DE_SIZE + 7] |= 0x3; + + uint16_t bcnt = (uint16_t)(-payload_size); + bcnt &= 0x0FFF; + bcnt |= 0xF000; + *(uint16_t *)&pcnet_tx_de_start[pcnet_tx_buffer_id * PCNET_DE_SIZE + 4] = bcnt; + + pcnet_tx_de_start[pcnet_tx_buffer_id * PCNET_DE_SIZE + 7] |= 0x80; + + write_csr32(0, read_csr32(0) | (1 << 3)); + + pcnet_tx_buffer_id = next_tx_index(pcnet_tx_buffer_id); +} + +static int pcnet_irq_handler(struct regs *r) { + + write_csr32(0, read_csr32(0) | 0x0400); + irq_ack(pcnet_irq); + + while (driver_owns(pcnet_rx_de_start, pcnet_rx_buffer_id)) { + uint16_t plen = *(uint16_t *)&pcnet_rx_de_start[pcnet_rx_buffer_id * PCNET_DE_SIZE + 8]; + + void * pbuf = (void *)(pcnet_rx_start + pcnet_rx_buffer_id * PCNET_BUFFER_SIZE); + + void * packet = malloc(plen); + memcpy(packet, pbuf, plen); + pcnet_rx_de_start[pcnet_rx_buffer_id * PCNET_DE_SIZE + 7] = 0x80; + + enqueue_packet(packet); + + pcnet_rx_buffer_id = next_rx_index(pcnet_rx_buffer_id); + } + wakeup_queue(rx_wait); + + return 1; +} + +static void pcnet_init(void * data, char * name) { + uint16_t command_reg = pci_read_field(pcnet_device_pci, PCI_COMMAND, 4) & 0xFFFF0000; + if (command_reg & (1 << 2)) { + debug_print(NOTICE, "Bus mastering already enabled.\n"); + } + command_reg |= (1 << 2); + command_reg |= (1 << 0); + pci_write_field(pcnet_device_pci, PCI_COMMAND, 4, command_reg); + + pcnet_io_base = pci_read_field(pcnet_device_pci, PCI_BAR0, 4) & 0xFFFFFFF0; + pcnet_mem_base = pci_read_field(pcnet_device_pci, PCI_BAR1, 4) & 0xFFFFFFF0; + + pcnet_irq = pci_read_field(pcnet_device_pci, PCI_INTERRUPT_LINE, 1); + irq_install_handler(pcnet_irq, pcnet_irq_handler); + + debug_print(NOTICE, "irq line: %d", pcnet_irq); + debug_print(NOTICE, "io base: 0x%x", pcnet_io_base); + + /* Read MAC from EEPROM */ + mac[0] = inportb(pcnet_io_base + 0); + mac[1] = inportb(pcnet_io_base + 1); + mac[2] = inportb(pcnet_io_base + 2); + mac[3] = inportb(pcnet_io_base + 3); + mac[4] = inportb(pcnet_io_base + 4); + mac[5] = inportb(pcnet_io_base + 5); + + /* Force reset */ + inportl(pcnet_io_base + 0x18); + inports(pcnet_io_base + 0x14); + + unsigned long s, ss; + relative_time(0, 10, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + + debug_print(NOTICE, "pcnet return from sleep"); + + /* set 32-bit mode */ + outportl(pcnet_io_base + 0x10, 0); + + /* SWSTYLE to 2 */ + uint32_t csr58 = read_csr32(58); + csr58 &= 0xFFF0; + csr58 |= 2; + write_csr32(58, csr58); + + /* ASEL enable */ + uint32_t bcr2 = read_bcr32(2); + bcr2 |= 0x2; + write_bcr32(2, bcr2); + + debug_print(NOTICE, "device mac %2x:%2x:%2x:%2x:%2x:%2x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + if (!pcnet_buffer_virt) { + debug_print(ERROR, "Failed."); + return; + } + + debug_print(WARNING, "phys: 0x%x, virt: 0x%x", pcnet_buffer_phys, pcnet_buffer_virt); + + pcnet_rx_de_start = pcnet_buffer_virt + 28; + pcnet_tx_de_start = pcnet_rx_de_start + PCNET_RX_COUNT * PCNET_DE_SIZE; + pcnet_rx_start = pcnet_tx_de_start + PCNET_TX_COUNT * PCNET_DE_SIZE; + pcnet_tx_start = pcnet_rx_start + PCNET_RX_COUNT * PCNET_BUFFER_SIZE; + + pcnet_rx_de_phys = virt_to_phys(pcnet_rx_de_start); + pcnet_tx_de_phys = virt_to_phys(pcnet_tx_de_start); + pcnet_rx_phys = virt_to_phys(pcnet_rx_start); + pcnet_tx_phys = virt_to_phys(pcnet_tx_start); + + /* set up descriptors */ + for (int i = 0; i < PCNET_RX_COUNT; i++) { + init_descriptor(i, 0); + } + + for (int i = 0; i < PCNET_TX_COUNT; i++) { + init_descriptor(i, 1); + } + + /* Set up device configuration structure */ + ((uint16_t *)&pcnet_buffer_virt[0])[0] = 0x0000; + pcnet_buffer_virt[2] = 5 << 4; /* RLEN << 4 */ + pcnet_buffer_virt[3] = 3 << 4; /* TLEN << 4 */ + pcnet_buffer_virt[4] = mac[0]; + pcnet_buffer_virt[5] = mac[1]; + pcnet_buffer_virt[6] = mac[2]; + pcnet_buffer_virt[7] = mac[3]; + pcnet_buffer_virt[8] = mac[4]; + pcnet_buffer_virt[9] = mac[5]; + + pcnet_buffer_virt[10] = 0; /* reserved */ + pcnet_buffer_virt[11] = 0; /* reserved */ + + pcnet_buffer_virt[12] = 0; + pcnet_buffer_virt[13] = 0; + pcnet_buffer_virt[14] = 0; + pcnet_buffer_virt[15] = 0; + pcnet_buffer_virt[16] = 0; + pcnet_buffer_virt[17] = 0; + pcnet_buffer_virt[18] = 0; + pcnet_buffer_virt[19] = 0; + + ((uint32_t *)&pcnet_buffer_virt[20])[0] = pcnet_rx_de_phys; + ((uint32_t *)&pcnet_buffer_virt[24])[0] = pcnet_tx_de_phys; + + /* Configure network */ + net_queue = list_create(); + rx_wait = list_create(); + + write_csr32(1, 0xFFFF & pcnet_buffer_phys); + write_csr32(2, 0xFFFF & (pcnet_buffer_phys >> 16)); + + uint32_t a = read_csr32(1); + uint32_t b = read_csr32(2); + debug_print(ERROR, "csr1 = 0x%4x csr2= 0x%4x", a, b); + + uint16_t csr3 = read_csr32(3); + if (csr3 & (1 << 10)) csr3 ^= (1 << 10); + if (csr3 & (1 << 2)) csr3 ^= (1 << 2); + csr3 |= (1 << 9); + csr3 |= (1 << 8); + write_csr32(3, csr3); /* Disable interrupt on init */ + write_csr32(4, read_csr32(4) | (1 << 1) | (1 << 12) | (1 << 14)); /* pad */ + + write_csr32(0, read_csr32(0) | (1 << 0) | (1 << 6)); /* do it */ + + uint64_t start_time; + asm volatile (".byte 0x0f, 0x31" : "=A" (start_time)); + + uint32_t status; + while (((status = read_csr32(0)) & (1 << 8)) == 0) { + uint64_t now_time; + asm volatile (".byte 0x0f, 0x31" : "=A" (now_time)); + if (now_time - start_time > 0x10000) { + debug_print(ERROR, "Could not initialize PCNet card, status is 0x%4x", status); + return; + } + } + + /* Start card */ + uint16_t csr0 = read_csr32(0); + if (csr0 & (1 << 0)) csr0 ^= (1 << 0); + if (csr0 & (1 << 2)) csr0 ^= (1 << 2); + csr0 |= (1 << 1); + write_csr32(0, csr0); + + debug_print(NOTICE, "Card start."); + + init_netif_funcs(pcnet_get_mac, dequeue_packet, pcnet_send_packet, "AMD PCnet FAST II/III"); + +} + +static int init(void) { + pci_scan(&find_pcnet, -1, &pcnet_device_pci); + + if (!pcnet_device_pci) { + debug_print(WARNING, "No PCNET device found."); + return 1; + } + + /* Initialize ring buffers */ + debug_print(WARNING, "Request a large continuous chunk of memory."); + /* This fits 32x1548 (rx) + 8x1548 (tx) + 32x16 (rx DE) + 8x16 (tx DE) */ + pcnet_buffer_virt = (void*)kvmalloc_p(0x10000, &pcnet_buffer_phys); + + create_kernel_tasklet(pcnet_init, "[pcnet]", NULL); + + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(pcnet, init, fini); +MODULE_DEPENDS(net); diff --git a/modules/pcspkr.c b/modules/pcspkr.c new file mode 100644 index 00000000..6a74b965 --- /dev/null +++ b/modules/pcspkr.c @@ -0,0 +1,72 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include + +static void note(int length, int freq) { + + uint32_t div = 11931800 / freq; + uint8_t t; + + outportb(0x43, 0xb6); + outportb(0x42, (uint8_t)(div)); + outportb(0x42, (uint8_t)(div >> 8)); + + t = inportb(0x61); + outportb(0x61, t | 0x3); + + unsigned long s, ss; + relative_time(0, length * 10, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + + t = inportb(0x61) & 0xFC; + outportb(0x61, t); + +} + +struct spkr { + int length; + int frequency; +}; + +static uint32_t write_spkr(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + if (!size % (sizeof(struct spkr))) { + return 0; + } + + struct spkr * s = (struct spkr *)buffer; + while ((uintptr_t)s < (uintptr_t)buffer + size) { + note(s->length, s->frequency); + s++; + } + + return (uintptr_t)s - (uintptr_t)buffer; +} + +static fs_node_t * spkr_device_create(void) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + sprintf(fnode->name, "spkr"); + fnode->mask = 0666; /* TODO need a speaker group */ + fnode->flags = FS_CHARDEVICE; + fnode->write = write_spkr; + return fnode; +} + +static int init(void) { + fs_node_t * node = spkr_device_create(); + vfs_mount("/dev/spkr", node); + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(pcspkr, init, fini); +MODULE_DEPENDS(debugshell); diff --git a/modules/procfs.c b/modules/procfs.c new file mode 100644 index 00000000..8e42e824 --- /dev/null +++ b/modules/procfs.c @@ -0,0 +1,547 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PROCFS_STANDARD_ENTRIES (sizeof(std_entries) / sizeof(struct procfs_entry)) +#define PROCFS_PROCDIR_ENTRIES (sizeof(procdir_entries) / sizeof(struct procfs_entry)) + +struct procfs_entry { + int id; + char * name; + read_type_t func; +}; + +static fs_node_t * procfs_generic_create(char * name, read_type_t read_func) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, name); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0444; + fnode->flags = FS_FILE; + fnode->read = read_func; + fnode->write = NULL; + fnode->open = NULL; + fnode->close = NULL; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ctime = now(); + fnode->mtime = now(); + fnode->atime = now(); + return fnode; +} + +static uint32_t proc_cmdline_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char buf[1024]; + process_t * proc = process_from_pid(node->inode); + + if (!proc) { + /* wat */ + return 0; + } + + if (!proc->cmdline) { + sprintf(buf, "%s", proc->name); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + return size; + } + + + buf[0] = '\0'; + + char * _buf = buf; + char ** args = proc->cmdline; + while (*args) { + strcpy(_buf, *args); + _buf += strlen(_buf); + if (*(args+1)) { + strcpy(_buf, "\036"); + _buf += strlen(_buf); + } + args++; + } + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + return size; +} + +static uint32_t proc_status_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char buf[2048]; + process_t * proc = process_from_pid(node->inode); + process_t * parent = process_get_parent(proc); + + if (!proc) { + /* wat */ + return 0; + } + + char state = process_is_ready(proc) ? 'R' : 'S'; + char * name = proc->name + strlen(proc->name) - 1; + + while (1) { + if (*name == '/') { + name++; + break; + } + if (name == proc->name) break; + name--; + } + + sprintf(buf, + "Name:\t%s\n" /* name */ + "State:\t%c\n" /* yeah, do this at some point */ + "Tgid:\t%d\n" /* group ? group : pid */ + "Pid:\t%d\n" /* pid */ + "PPid:\t%d\n" /* parent pid */ + "Uid:\t%d\n" + "Ueip:\t0x%x\n" + "SCid:\t%d\n" + "SC0:\t0x%x\n" + "SC1:\t0x%x\n" + "SC2:\t0x%x\n" + "SC3:\t0x%x\n" + "SC4:\t0x%x\n" + "Path:\t%s\n" + , + name, + state, + proc->group ? proc->group : proc->id, + proc->id, + parent ? parent->id : 0, + proc->user, + proc->syscall_registers ? proc->syscall_registers->eip : 0, + proc->syscall_registers ? proc->syscall_registers->eax : 0, + proc->syscall_registers ? proc->syscall_registers->ebx : 0, + proc->syscall_registers ? proc->syscall_registers->ecx : 0, + proc->syscall_registers ? proc->syscall_registers->edx : 0, + proc->syscall_registers ? proc->syscall_registers->esi : 0, + proc->syscall_registers ? proc->syscall_registers->edi : 0, + proc->cmdline ? proc->cmdline[0] : "(none)" + ); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + return size; +} + +static struct procfs_entry procdir_entries[] = { + {1, "cmdline", proc_cmdline_func}, + {2, "status", proc_status_func}, +}; + +static struct dirent * readdir_procfs_procdir(fs_node_t *node, uint32_t index) { + if (index == 0) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, "."); + return out; + } + + if (index == 1) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, ".."); + return out; + } + + index -= 2; + + if (index < PROCFS_PROCDIR_ENTRIES) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = procdir_entries[index].id; + strcpy(out->name, procdir_entries[index].name); + return out; + } + return NULL; +} + +static fs_node_t * finddir_procfs_procdir(fs_node_t * node, char * name) { + if (!name) return NULL; + + for (unsigned int i = 0; i < PROCFS_PROCDIR_ENTRIES; ++i) { + if (!strcmp(name, procdir_entries[i].name)) { + fs_node_t * out = procfs_generic_create(procdir_entries[i].name, procdir_entries[i].func); + out->inode = node->inode; + return out; + } + } + + return NULL; +} + + +static fs_node_t * procfs_procdir_create(process_t * process) { + pid_t pid = process->id; + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = pid; + sprintf(fnode->name, "%d", pid); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0555; + fnode->flags = FS_DIRECTORY; + fnode->read = NULL; + fnode->write = NULL; + fnode->open = NULL; + fnode->close = NULL; + fnode->readdir = readdir_procfs_procdir; + fnode->finddir = finddir_procfs_procdir; + fnode->nlink = 1; + fnode->ctime = process->start.tv_sec; + fnode->mtime = process->start.tv_sec; + fnode->atime = process->start.tv_sec; + return fnode; +} + +static uint32_t cpuinfo_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + return 0; +} + +extern uintptr_t heap_end; +extern uintptr_t kernel_heap_alloc_point; + +static uint32_t meminfo_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char buf[1024]; + unsigned int total = memory_total(); + unsigned int free = total - memory_use(); + unsigned int kheap = (heap_end - kernel_heap_alloc_point) / 1024; + sprintf(buf, + "MemTotal: %d kB\n" + "MemFree: %d kB\n" + "KHeapUse: %d kB\n" + , total, free, kheap); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + return size; +} + +static uint32_t uptime_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char buf[1024]; + sprintf(buf, "%d.%3d\n", timer_ticks, timer_subticks); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + return size; +} + +static uint32_t cmdline_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char buf[1024]; + extern char * cmdline; + sprintf(buf, "%s\n", cmdline ? cmdline : ""); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + return size; +} + +static uint32_t version_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char buf[1024]; + char version_number[512]; + sprintf(version_number, __kernel_version_format, + __kernel_version_major, + __kernel_version_minor, + __kernel_version_lower, + __kernel_version_suffix); + sprintf(buf, "%s %s %s %s %s %s\n", + __kernel_name, + version_number, + __kernel_version_codename, + __kernel_build_date, + __kernel_build_time, + __kernel_arch); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf + offset, size); + return size; +} + +static uint32_t compiler_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char buf[1024]; + sprintf(buf, "%s\n", __kernel_compiler_version); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf, size); + return size; +} + +extern tree_t * fs_tree; /* kernel/fs/vfs.c */ + +static void mount_recurse(char * buf, tree_node_t * node, size_t height) { + /* End recursion on a blank entry */ + if (!node) return; + char * tmp = malloc(512); + memset(tmp, 0, 512); + char * c = tmp; + /* Indent output */ + for (uint32_t i = 0; i < height; ++i) { + c += sprintf(c, " "); + } + /* Get the current process */ + struct vfs_entry * fnode = (struct vfs_entry *)node->value; + /* Print the process name */ + if (fnode->file) { + c += sprintf(c, "%s → %s 0x%x (%s, %s)", fnode->name, fnode->device, fnode->file, fnode->fs_type, fnode->file->name); + } else { + c += sprintf(c, "%s → (empty)", fnode->name); + } + /* Linefeed */ + sprintf(buf+strlen(buf),"%s\n",tmp); + free(tmp); + foreach(child, node->children) { + /* Recursively print the children */ + mount_recurse(buf+strlen(buf),child->value, height + 1); + } +} + +static uint32_t mounts_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char * buf = malloc(4096); + + buf[0] = '\0'; + + mount_recurse(buf, fs_tree->root, 0); + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf, size); + free(buf); + return size; +} + +static uint32_t netif_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + char * buf = malloc(4096); + + /* In order to not directly depend on the network module, we dynamically locate the symbols we need. */ + void (*ip_ntoa)(uint32_t, char *) = (void (*)(uint32_t,char*))(uintptr_t)hashmap_get(modules_get_symbols(),"ip_ntoa"); + + struct netif * (*get_netif)(void) = (struct netif *(*)(void))(uintptr_t)hashmap_get(modules_get_symbols(),"get_default_network_interface"); + + uint32_t (*get_dns)(void) = (uint32_t (*)(void))(uintptr_t)hashmap_get(modules_get_symbols(),"get_primary_dns"); + + if (get_netif) { + struct netif * netif = get_netif(); + char ip[16]; + ip_ntoa(netif->source, ip); + char dns[16]; + ip_ntoa(get_dns(), dns); + char gw[16]; + ip_ntoa(netif->gateway, gw); + + if (netif->hwaddr[0] == 0 && + netif->hwaddr[1] == 0 && + netif->hwaddr[2] == 0 && + netif->hwaddr[3] == 0 && + netif->hwaddr[4] == 0 && + netif->hwaddr[5] == 0) { + + sprintf(buf, "no network\n"); + } else { + sprintf(buf, + "ip:\t%s\n" + "mac:\t%2x:%2x:%2x:%2x:%2x:%2x\n" + "device:\t%s\n" + "dns:\t%s\n" + "gateway:\t%s\n" + , + ip, + netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5], + netif->driver, + dns, + gw + ); + } + } else { + sprintf(buf, "no network\n"); + } + + size_t _bsize = strlen(buf); + if (offset > _bsize) return 0; + if (size > _bsize - offset) size = _bsize - offset; + + memcpy(buffer, buf, size); + free(buf); + return size; + +} + +static struct procfs_entry std_entries[] = { + {-1, "cpuinfo", cpuinfo_func}, + {-2, "meminfo", meminfo_func}, + {-3, "uptime", uptime_func}, + {-4, "cmdline", cmdline_func}, + {-5, "version", version_func}, + {-6, "compiler", compiler_func}, + {-7, "mounts", mounts_func}, + {-8, "netif", netif_func}, +}; + +static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) { + if (index == 0) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, "."); + return out; + } + + if (index == 1) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, ".."); + return out; + } + + if (index == 2) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, "self"); + return out; + } + + index -= 3; + + if (index < PROCFS_STANDARD_ENTRIES) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = std_entries[index].id; + strcpy(out->name, std_entries[index].name); + return out; + } + int i = index - PROCFS_STANDARD_ENTRIES + 1; + + debug_print(WARNING, "%d %d %d", i, index, PROCFS_STANDARD_ENTRIES); + + pid_t pid = 0; + + foreach(lnode, process_list) { + i--; + if (i == 0) { + process_t * proc = (process_t *)lnode->value; + pid = proc->id; + break; + } + } + + if (pid == 0) { + return NULL; + } + + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = pid; + sprintf(out->name, "%d", pid); + + return out; +} + +static fs_node_t * finddir_procfs_root(fs_node_t * node, char * name) { + if (!name) return NULL; + if (strlen(name) < 1) return NULL; + + if (name[0] >= '0' && name[0] <= '9') { + /* XXX process entries */ + pid_t pid = atoi(name); + process_t * proc = process_from_pid(pid); + if (!proc) { + return NULL; + } + fs_node_t * out = procfs_procdir_create(proc); + return out; + } + + if (!strcmp(name,"self")) { + return procfs_procdir_create((process_t *)current_process); + } + + for (unsigned int i = 0; i < PROCFS_STANDARD_ENTRIES; ++i) { + if (!strcmp(name, std_entries[i].name)) { + fs_node_t * out = procfs_generic_create(std_entries[i].name, std_entries[i].func); + return out; + } + } + + return NULL; +} + + +static fs_node_t * procfs_create(void) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, "proc"); + fnode->mask = 0555; + fnode->uid = 0; + fnode->gid = 0; + fnode->flags = FS_DIRECTORY; + fnode->read = NULL; + fnode->write = NULL; + fnode->open = NULL; + fnode->close = NULL; + fnode->readdir = readdir_procfs_root; + fnode->finddir = finddir_procfs_root; + fnode->nlink = 1; + fnode->ctime = now(); + fnode->mtime = now(); + fnode->atime = now(); + return fnode; +} + +int procfs_initialize(void) { + /* TODO Move this to some sort of config */ + vfs_mount("/proc", procfs_create()); + + debug_print_vfs_tree(); + return 0; +} + +int procfs_finalize(void) { + return 0; +} + +MODULE_DEF(procfs, procfs_initialize, procfs_finalize); diff --git a/modules/ps2kbd.c b/modules/ps2kbd.c new file mode 100644 index 00000000..04f2e6d9 --- /dev/null +++ b/modules/ps2kbd.c @@ -0,0 +1,82 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2011-2015 Kevin Lange + * + * Low-level keyboard interrupt driver. + * + * Creates a device file (keyboard_pipe) that can be read + * to retreive keyboard events. + * + */ + +#include +#include +#include +#include +#include + +#include + +#define KEY_DEVICE 0x60 +#define KEY_PENDING 0x64 +#define KEY_IRQ 1 + +static fs_node_t * keyboard_pipe; + +/* + * Wait on the keyboard. + */ +static void keyboard_wait(void) { + while(inportb(KEY_PENDING) & 2); +} + +/* + * Keyboard interrupt callback + */ +static int keyboard_handler(struct regs *r) { + unsigned char scancode; + if (inportb(KEY_PENDING) & 0x01) { + scancode = inportb(KEY_DEVICE); + + write_fs(keyboard_pipe, 0, 1, (uint8_t []){scancode}); + } + + irq_ack(KEY_IRQ); + return 1; +} + +/* + * Install the keyboard driver and initialize the + * pipe device for userspace. + */ +static int keyboard_install(void) { + debug_print(NOTICE, "Initializing PS/2 keyboard driver"); + + /* Create a device pipe */ + keyboard_pipe = make_pipe(128); + current_process->fds->entries[0] = keyboard_pipe; + + keyboard_pipe->flags = FS_CHARDEVICE; + + vfs_mount("/dev/kbd", keyboard_pipe); + + /* Install the interrupt handler */ + irq_install_handler(KEY_IRQ, keyboard_handler); + + return 0; +} + +static void keyboard_reset_ps2(void) { + uint8_t tmp = inportb(0x61); + outportb(0x61, tmp | 0x80); + outportb(0x61, tmp & 0x7F); + inportb(KEY_DEVICE); +} + +static int keyboard_uninstall(void) { + /* TODO */ + return 0; +} + +MODULE_DEF(ps2kbd, keyboard_install, keyboard_uninstall); diff --git a/modules/ps2mouse.c b/modules/ps2mouse.c new file mode 100644 index 00000000..5e17f295 --- /dev/null +++ b/modules/ps2mouse.c @@ -0,0 +1,232 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + * + * Mouse driver + * + */ +#include +#include +#include +#include +#include +#include + +static uint8_t mouse_cycle = 0; +static uint8_t mouse_byte[4]; + +#define PACKETS_IN_PIPE 1024 +#define DISCARD_POINT 32 + +#define MOUSE_IRQ 12 + +#define MOUSE_PORT 0x60 +#define MOUSE_STATUS 0x64 +#define MOUSE_ABIT 0x02 +#define MOUSE_BBIT 0x01 +#define MOUSE_WRITE 0xD4 +#define MOUSE_F_BIT 0x20 +#define MOUSE_V_BIT 0x08 + +#define MOUSE_DEFAULT 0 +#define MOUSE_SCROLLWHEEL 1 +#define MOUSE_BUTTONS 2 + +static int8_t mouse_mode = MOUSE_DEFAULT; + +static fs_node_t * mouse_pipe; + +void (*ps2_mouse_alternate)(void) = NULL; + +static void mouse_wait(uint8_t a_type) { + uint32_t timeout = 100000; + if (!a_type) { + while (--timeout) { + if ((inportb(MOUSE_STATUS) & MOUSE_BBIT) == 1) { + return; + } + } + debug_print(INFO, "mouse timeout"); + return; + } else { + while (--timeout) { + if (!((inportb(MOUSE_STATUS) & MOUSE_ABIT))) { + return; + } + } + debug_print(INFO, "mouse timeout"); + return; + } +} + +static void mouse_write(uint8_t write) { + mouse_wait(1); + outportb(MOUSE_STATUS, MOUSE_WRITE); + mouse_wait(1); + outportb(MOUSE_PORT, write); +} + +static uint8_t mouse_read(void) { + mouse_wait(0); + char t = inportb(MOUSE_PORT); + return t; +} + +static int mouse_handler(struct regs *r) { + uint8_t status = inportb(MOUSE_STATUS); + while ((status & MOUSE_BBIT) && (status & MOUSE_F_BIT)) { + if (ps2_mouse_alternate) { + ps2_mouse_alternate(); + break; + } + int8_t mouse_in = inportb(MOUSE_PORT); + switch (mouse_cycle) { + case 0: + mouse_byte[0] = mouse_in; + if (!(mouse_in & MOUSE_V_BIT)) break; + ++mouse_cycle; + break; + case 1: + mouse_byte[1] = mouse_in; + ++mouse_cycle; + break; + case 2: + mouse_byte[2] = mouse_in; + if (mouse_mode == MOUSE_SCROLLWHEEL || mouse_mode == MOUSE_BUTTONS) { + ++mouse_cycle; + break; + } + goto finish_packet; + case 3: + mouse_byte[3] = mouse_in; + goto finish_packet; + } + goto read_next; +finish_packet: + mouse_cycle = 0; + /* We now have a full mouse packet ready to use */ + mouse_device_packet_t packet; + packet.magic = MOUSE_MAGIC; + int x = mouse_byte[1]; + int y = mouse_byte[2]; + if (x && mouse_byte[0] & (1 << 4)) { + /* Sign bit */ + x = x - 0x100; + } + if (y && mouse_byte[0] & (1 << 5)) { + /* Sign bit */ + y = y - 0x100; + } + if (mouse_byte[0] & (1 << 6) || mouse_byte[0] & (1 << 7)) { + /* Overflow */ + x = 0; + y = 0; + } + packet.x_difference = x; + packet.y_difference = y; + packet.buttons = 0; + if (mouse_byte[0] & 0x01) { + packet.buttons |= LEFT_CLICK; + } + if (mouse_byte[0] & 0x02) { + packet.buttons |= RIGHT_CLICK; + } + if (mouse_byte[0] & 0x04) { + packet.buttons |= MIDDLE_CLICK; + } + + if (mouse_mode == MOUSE_SCROLLWHEEL && mouse_byte[3]) { + if ((int8_t)mouse_byte[3] > 0) { + packet.buttons |= MOUSE_SCROLL_DOWN; + } else if ((int8_t)mouse_byte[3] < 0) { + packet.buttons |= MOUSE_SCROLL_UP; + } + } + + mouse_device_packet_t bitbucket; + while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { + read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); + } + write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); +read_next: + break; + } + irq_ack(MOUSE_IRQ); + return 1; +} + +static int ioctl_mouse(fs_node_t * node, int request, void * argp) { + if (request == 1) { + mouse_cycle = 0; + return 0; + } + return -1; +} + +static int mouse_install(void) { + debug_print(NOTICE, "Initializing PS/2 mouse interface"); + uint8_t status, result; + IRQ_OFF; + mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); + mouse_wait(1); + outportb(MOUSE_STATUS, 0xA8); + mouse_read(); + mouse_wait(1); + outportb(MOUSE_STATUS, 0x20); + mouse_wait(0); + status = inportb(0x60) | 3; + mouse_wait(1); + outportb(MOUSE_STATUS, 0x60); + mouse_wait(1); + outportb(MOUSE_PORT, status); + mouse_write(0xF6); + mouse_read(); + mouse_write(0xF4); + mouse_read(); + /* Try to enable scroll wheel (but not buttons) */ + if (!args_present("nomousescroll")) { + mouse_write(0xF2); + mouse_read(); + result = mouse_read(); + mouse_write(0xF3); + mouse_read(); + mouse_write(200); + mouse_read(); + mouse_write(0xF3); + mouse_read(); + mouse_write(100); + mouse_read(); + mouse_write(0xF3); + mouse_read(); + mouse_write(80); + mouse_read(); + mouse_write(0xF2); + mouse_read(); + result = mouse_read(); + if (result == 3) { + mouse_mode = MOUSE_SCROLLWHEEL; + } + } + + irq_install_handler(MOUSE_IRQ, mouse_handler); + IRQ_RES; + + uint8_t tmp = inportb(0x61); + outportb(0x61, tmp | 0x80); + outportb(0x61, tmp & 0x7F); + inportb(MOUSE_PORT); + + mouse_pipe->flags = FS_CHARDEVICE; + mouse_pipe->ioctl = ioctl_mouse; + + vfs_mount("/dev/mouse", mouse_pipe); + return 0; +} + +static int mouse_uninstall(void) { + /* TODO */ + return 0; +} + +MODULE_DEF(ps2mouse, mouse_install, mouse_uninstall); diff --git a/modules/random.c b/modules/random.c new file mode 100644 index 00000000..f01c4172 --- /dev/null +++ b/modules/random.c @@ -0,0 +1,73 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + * + * Provides access to the kernel RNG + * + */ + +#include +#include +#include + +#include + +static uint32_t read_random(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static uint32_t write_random(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static void open_random(fs_node_t *node, unsigned int flags); +static void close_random(fs_node_t *node); + +static uint32_t read_random(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + uint32_t s = 0; + while (s < size) { + buffer[s] = krand() % 0xFF; + offset++; + s++; + } + return size; +} + +static uint32_t write_random(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + return size; +} + +static void open_random(fs_node_t * node, unsigned int flags) { + return; +} + +static void close_random(fs_node_t * node) { + return; +} + +static fs_node_t * random_device_create(void) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, "random"); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0444; + fnode->length = 1024; + fnode->flags = FS_CHARDEVICE; + fnode->read = read_random; + fnode->write = write_random; + fnode->open = open_random; + fnode->close = close_random; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; + return fnode; +} + +static int random_initialize(void) { + vfs_mount("/dev/random", random_device_create()); + vfs_mount("/dev/urandom", random_device_create()); + return 0; +} + +static int random_finalize(void) { + return 0; +} + +MODULE_DEF(random, random_initialize, random_finalize); diff --git a/modules/rtl.c b/modules/rtl.c new file mode 100644 index 00000000..4743371e --- /dev/null +++ b/modules/rtl.c @@ -0,0 +1,420 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* XXX move this to ipv4? */ +extern size_t print_dns_name(fs_node_t * tty, struct dns_packet * dns, size_t offset); + +static uint32_t rtl_device_pci = 0x00000000; + +static void find_rtl(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + if ((vendorid == 0x10ec) && (deviceid == 0x8139)) { + *((uint32_t *)extra) = device; + } +} + +#define RTL_PORT_MAC 0x00 +#define RTL_PORT_MAR 0x08 +#define RTL_PORT_TXSTAT 0x10 +#define RTL_PORT_TXBUF 0x20 +#define RTL_PORT_RBSTART 0x30 +#define RTL_PORT_CMD 0x37 +#define RTL_PORT_RXPTR 0x38 +#define RTL_PORT_RXADDR 0x3A +#define RTL_PORT_IMR 0x3C +#define RTL_PORT_ISR 0x3E +#define RTL_PORT_TCR 0x40 +#define RTL_PORT_RCR 0x44 +#define RTL_PORT_RXMISS 0x4C +#define RTL_PORT_CONFIG 0x52 + +static list_t * net_queue = NULL; + +static spin_lock_t net_queue_lock = { 0 }; + +static int rtl_irq = 0; +static uint32_t rtl_iobase = 0; +static uint8_t * rtl_rx_buffer; +static uint8_t * rtl_tx_buffer[5]; +static uint8_t mac[6]; + +static uint8_t * last_packet = NULL; + +static uintptr_t rtl_rx_phys; +static uintptr_t rtl_tx_phys[5]; + +static uint32_t cur_rx = 0; +static int dirty_tx = 0; +static int next_tx = 0; + +static list_t * rx_wait; + +static spin_lock_t _lock; +static int next_tx_buf(void) { + int out; + spin_lock(_lock); + out = next_tx; + next_tx++; + if (next_tx == 4) { + next_tx = 0; + } + spin_unlock(_lock); + return out; +} + +void* rtl_dequeue() { + while (!net_queue->length) { + sleep_on(rx_wait); + } + + spin_lock(net_queue_lock); + node_t * n = list_dequeue(net_queue); + void* value = (struct ethernet_packet *)n->value; + free(n); + spin_unlock(net_queue_lock); + + return value; +} + +void rtl_enqueue(void * buffer) { + /* XXX size? source? */ + spin_lock(net_queue_lock); + list_insert(net_queue, buffer); + spin_unlock(net_queue_lock); +} + +uint8_t* rtl_get_mac() { + return mac; +} + +void rtl_send_packet(uint8_t* payload, size_t payload_size) { + int my_tx = next_tx_buf(); + memcpy(rtl_tx_buffer[my_tx], payload, payload_size); + + outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); + outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, payload_size); +} + +struct ethernet_packet* rtl_get_packet(void) { + return (struct ethernet_packet*)rtl_dequeue(); +} + +static int rtl_irq_handler(struct regs *r) { + uint16_t status = inports(rtl_iobase + RTL_PORT_ISR); + if (!status) { + return 0; + } + outports(rtl_iobase + RTL_PORT_ISR, status); + + irq_ack(rtl_irq); + + if (status & 0x01 || status & 0x02) { + /* Receive */ + while((inportb(rtl_iobase + RTL_PORT_CMD) & 0x01) == 0) { + int offset = cur_rx % 0x2000; + +#if 0 + uint16_t buf_addr = inports(rtl_iobase + RTL_PORT_RXADDR); + uint16_t buf_ptr = inports(rtl_iobase + RTL_PORT_RXPTR); + uint8_t cmd = inportb(rtl_iobase + RTL_PORT_CMD); +#endif + + uint32_t * buf_start = (uint32_t *)((uintptr_t)rtl_rx_buffer + offset); + uint32_t rx_status = buf_start[0]; + int rx_size = rx_status >> 16; + + if (rx_status & (0x0020 | 0x0010 | 0x0004 | 0x0002)) { + debug_print(WARNING, "rx error :("); + } else { + uint8_t * buf_8 = (uint8_t *)&(buf_start[1]); + + last_packet = malloc(rx_size); + + uintptr_t packet_end = (uintptr_t)buf_8 + rx_size; + if (packet_end > (uintptr_t)rtl_rx_buffer + 0x2000) { + size_t s = ((uintptr_t)rtl_rx_buffer + 0x2000) - (uintptr_t)buf_8; + memcpy(last_packet, buf_8, s); + memcpy((void *)((uintptr_t)last_packet + s), rtl_rx_buffer, rx_size - s); + } else { + memcpy(last_packet, buf_8, rx_size); + } + + rtl_enqueue(last_packet); + } + + cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; + outports(rtl_iobase + RTL_PORT_RXPTR, cur_rx - 16); + } + wakeup_queue(rx_wait); + } + + if (status & 0x08 || status & 0x04) { + unsigned int i = inportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * dirty_tx); + (void)i; + dirty_tx++; + if (dirty_tx == 5) dirty_tx = 0; + } + + return 1; +} + +#if 0 +static void rtl_netd(void * data, char * name) { + fs_node_t * tty = data; + + { + fprintf(tty, "Sending DNS query...\n"); + uint8_t queries[] = { + 3,'i','r','c', + 8,'f','r','e','e','n','o','d','e', + 3,'n','e','t', + 0, + 0x00, 0x01, /* A */ + 0x00, 0x01, /* IN */ + }; + + int my_tx = next_tx_buf(); + size_t packet_size = write_dns_packet(rtl_tx_buffer[my_tx], sizeof(queries), queries); + + outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); + outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size); + } + + sleep_on(rx_wait); + parse_dns_response(tty, last_packet); + + { + fprintf(tty, "Sending DNS query...\n"); + uint8_t queries[] = { + 7,'n','y','a','n','c','a','t', + 5,'d','a','k','k','o', + 2,'u','s', + 0, + 0x00, 0x01, /* A */ + 0x00, 0x01, /* IN */ + }; + + int my_tx = next_tx_buf(); + size_t packet_size = write_dns_packet(rtl_tx_buffer[my_tx], sizeof(queries), queries); + + outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); + outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size); + } + + sleep_on(rx_wait); + parse_dns_response(tty, last_packet); + + seq_no = krand(); + + { + fprintf(tty, "Sending TCP syn\n"); + int my_tx = next_tx_buf(); + uint8_t payload[] = { 0 }; + size_t packet_size = write_tcp_packet(rtl_tx_buffer[my_tx], payload, 0, (TCP_FLAGS_SYN | DATA_OFFSET_5)); + + outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); + outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size); + + seq_no += 1; + ack_no = 0; + } + + { + struct ethernet_packet * eth = net_receive(); + uint16_t eth_type = ntohs(eth->type); + + fprintf(tty, "Ethernet II, Src: (%2x:%2x:%2x:%2x:%2x:%2x), Dst: (%2x:%2x:%2x:%2x:%2x:%2x) [type=%4x)\n", + eth->source[0], eth->source[1], eth->source[2], + eth->source[3], eth->source[4], eth->source[5], + eth->destination[0], eth->destination[1], eth->destination[2], + eth->destination[3], eth->destination[4], eth->destination[5], + eth_type); + + + struct ipv4_packet * ipv4 = (struct ipv4_packet *)eth->payload; + uint32_t src_addr = ntohl(ipv4->source); + uint32_t dst_addr = ntohl(ipv4->destination); + uint16_t length = ntohs(ipv4->length); + + char src_ip[16]; + char dst_ip[16]; + + ip_ntoa(src_addr, src_ip); + ip_ntoa(dst_addr, dst_ip); + + fprintf(tty, "IP packet [%s → %s] length=%d bytes\n", + src_ip, dst_ip, length); + + struct tcp_header * tcp = (struct tcp_header *)ipv4->payload; + + if (seq_no != ntohl(tcp->ack_number)) { + fprintf(tty, "[eth] Expected ack number of 0x%x, got 0x%x\n", + seq_no, + ntohl(tcp->ack_number)); + fprintf(tty, "[eth] Bailing...\n"); + return; + } + + ack_no = ntohl(tcp->seq_number) + 1; + free(eth); + } + + { + fprintf(tty, "Sending TCP ack\n"); + int my_tx = next_tx_buf(); + uint8_t payload[] = { 0 }; + size_t packet_size = write_tcp_packet(rtl_tx_buffer[my_tx], payload, 0, (TCP_FLAGS_ACK | DATA_OFFSET_5)); + + outportl(rtl_iobase + RTL_PORT_TXBUF + 4 * my_tx, rtl_tx_phys[my_tx]); + outportl(rtl_iobase + RTL_PORT_TXSTAT + 4 * my_tx, packet_size); + } + + fprintf(tty, "[eth] s-next=0x%x, r-next=0x%x\n", seq_no, ack_no); + +} +#endif + +int init_rtl(void) { + if (rtl_device_pci) { + debug_print(NOTICE, "Located an RTL 8139: 0x%x\n", rtl_device_pci); + + uint16_t command_reg = pci_read_field(rtl_device_pci, PCI_COMMAND, 4); + debug_print(NOTICE, "COMMAND register before: 0x%4x\n", command_reg); + if (command_reg & (1 << 2)) { + debug_print(NOTICE, "Bus mastering already enabled.\n"); + } else { + command_reg |= (1 << 2); /* bit 2 */ + debug_print(NOTICE, "COMMAND register after: 0x%4x\n", command_reg); + pci_write_field(rtl_device_pci, PCI_COMMAND, 4, command_reg); + command_reg = pci_read_field(rtl_device_pci, PCI_COMMAND, 4); + debug_print(NOTICE, "COMMAND register after: 0x%4x\n", command_reg); + } + + rtl_irq = pci_read_field(rtl_device_pci, PCI_INTERRUPT_LINE, 1); + debug_print(NOTICE, "Interrupt Line: %x\n", rtl_irq); + irq_install_handler(rtl_irq, rtl_irq_handler); + + uint32_t rtl_bar0 = pci_read_field(rtl_device_pci, PCI_BAR0, 4); + uint32_t rtl_bar1 = pci_read_field(rtl_device_pci, PCI_BAR1, 4); + + debug_print(NOTICE, "BAR0: 0x%8x\n", rtl_bar0); + debug_print(NOTICE, "BAR1: 0x%8x\n", rtl_bar1); + + rtl_iobase = 0x00000000; + + if (rtl_bar0 & 0x00000001) { + rtl_iobase = rtl_bar0 & 0xFFFFFFFC; + } else { + debug_print(NOTICE, "This doesn't seem right! RTL8139 should be using an I/O BAR; this looks like a memory bar."); + } + + debug_print(NOTICE, "RTL iobase: 0x%x\n", rtl_iobase); + + rx_wait = list_create(); + + debug_print(NOTICE, "Determining mac address...\n"); + for (int i = 0; i < 6; ++i) { + mac[i] = inports(rtl_iobase + RTL_PORT_MAC + i); + } + + debug_print(NOTICE, "%2x:%2x:%2x:%2x:%2x:%2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + debug_print(NOTICE, "Enabling RTL8139.\n"); + outportb(rtl_iobase + RTL_PORT_CONFIG, 0x0); + + debug_print(NOTICE, "Resetting RTL8139.\n"); + outportb(rtl_iobase + RTL_PORT_CMD, 0x10); + while ((inportb(rtl_iobase + 0x37) & 0x10) != 0) { } + + debug_print(NOTICE, "Done resetting RTL8139.\n"); + + for (int i = 0; i < 5; ++i) { + rtl_tx_buffer[i] = (void*)kvmalloc_p(0x1000, &rtl_tx_phys[i]); + for (int j = 0; j < 60; ++j) { + rtl_tx_buffer[i][j] = 0xF0; + } + } + + rtl_rx_buffer = (uint8_t *)kvmalloc_p(0x3000, &rtl_rx_phys); + memset(rtl_rx_buffer, 0x00, 0x3000); + + debug_print(NOTICE, "Buffers:\n"); + debug_print(NOTICE, " rx 0x%x [phys 0x%x and 0x%x and 0x%x]\n", rtl_rx_buffer, rtl_rx_phys, map_to_physical((uintptr_t)rtl_rx_buffer + 0x1000), map_to_physical((uintptr_t)rtl_rx_buffer + 0x2000)); + + for (int i = 0; i < 5; ++i) { + debug_print(NOTICE, " tx 0x%x [phys 0x%x]\n", rtl_tx_buffer[i], rtl_tx_phys[i]); + } + + debug_print(NOTICE, "Initializing receive buffer.\n"); + outportl(rtl_iobase + RTL_PORT_RBSTART, rtl_rx_phys); + + debug_print(NOTICE, "Enabling IRQs.\n"); + outports(rtl_iobase + RTL_PORT_IMR, + 0x8000 | /* PCI error */ + 0x4000 | /* PCS timeout */ + 0x40 | /* Rx FIFO over */ + 0x20 | /* Rx underrun */ + 0x10 | /* Rx overflow */ + 0x08 | /* Tx error */ + 0x04 | /* Tx okay */ + 0x02 | /* Rx error */ + 0x01 /* Rx okay */ + ); /* TOK, ROK */ + + debug_print(NOTICE, "Configuring transmit\n"); + outportl(rtl_iobase + RTL_PORT_TCR, + 0 + ); + + debug_print(NOTICE, "Configuring receive buffer.\n"); + outportl(rtl_iobase + RTL_PORT_RCR, + (0) | /* 8K receive */ + 0x08 | /* broadcast */ + 0x01 /* all physical */ + ); + + debug_print(NOTICE, "Enabling receive and transmit.\n"); + outportb(rtl_iobase + RTL_PORT_CMD, 0x08 | 0x04); + + debug_print(NOTICE, "Resetting rx stats\n"); + outportl(rtl_iobase + RTL_PORT_RXMISS, 0); + + net_queue = list_create(); + + debug_print(NOTICE, "Initializing netif functions\n"); + init_netif_funcs(rtl_get_mac, rtl_get_packet, rtl_send_packet, "RTL8139"); + + debug_print(NOTICE, "Back from starting the worker thread.\n"); + } else { + return -1; + } + return 0; +} + +static int init(void) { + pci_scan(&find_rtl, -1, &rtl_device_pci); + if (!rtl_device_pci) { + debug_print(ERROR, "No RTL 8139 found?"); + return 1; + } + init_rtl(); + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(rtl, init, fini); +MODULE_DEPENDS(net); diff --git a/modules/serial.c b/modules/serial.c new file mode 100644 index 00000000..457c8e3d --- /dev/null +++ b/modules/serial.c @@ -0,0 +1,218 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + * + * Serial communication device + * + */ + +#include +#include +#include +#include +#include +#include + +#define SERIAL_PORT_A 0x3F8 +#define SERIAL_PORT_B 0x2F8 +#define SERIAL_PORT_C 0x3E8 +#define SERIAL_PORT_D 0x2E8 + +#define SERIAL_IRQ_AC 4 +#define SERIAL_IRQ_BD 3 + +static char serial_recv(int device); + +static fs_node_t * _serial_port_a = NULL; +static fs_node_t * _serial_port_b = NULL; +static fs_node_t * _serial_port_c = NULL; +static fs_node_t * _serial_port_d = NULL; + +static uint8_t convert(uint8_t in) { + switch (in) { + case 0x7F: + return 0x08; + case 0x0D: + return '\n'; + default: + return in; + } +} + +static fs_node_t ** pipe_for_port(int port) { + switch (port) { + case SERIAL_PORT_A: return &_serial_port_a; + case SERIAL_PORT_B: return &_serial_port_b; + case SERIAL_PORT_C: return &_serial_port_c; + case SERIAL_PORT_D: return &_serial_port_d; + } + __builtin_unreachable(); +} + +static int serial_handler_ac(struct regs *r) { + char serial; + int port = 0; + if (inportb(SERIAL_PORT_A+1) & 0x01) { + port = SERIAL_PORT_A; + } else { + port = SERIAL_PORT_C; + } + serial = serial_recv(port); + irq_ack(SERIAL_IRQ_AC); + uint8_t buf[] = {convert(serial), 0}; + write_fs(*pipe_for_port(port), 0, 1, buf); + return 1; +} + +static int serial_handler_bd(struct regs *r) { + char serial; + int port = 0; + debug_print(NOTICE, "Received something on secondary port"); + if (inportb(SERIAL_PORT_B+1) & 0x01) { + port = SERIAL_PORT_B; + } else { + port = SERIAL_PORT_D; + } + serial = serial_recv(port); + irq_ack(SERIAL_IRQ_BD); + uint8_t buf[] = {convert(serial), 0}; + write_fs(*pipe_for_port(port), 0, 1, buf); + return 1; +} + +static void serial_enable(int port) { + outportb(port + 1, 0x00); /* Disable interrupts */ + outportb(port + 3, 0x80); /* Enable divisor mode */ + outportb(port + 0, 0x01); /* Div Low: 01 Set the port to 115200 bps */ + outportb(port + 1, 0x00); /* Div High: 00 */ + outportb(port + 3, 0x03); /* Disable divisor mode, set parity */ + outportb(port + 2, 0xC7); /* Enable FIFO and clear */ + outportb(port + 4, 0x0B); /* Enable interrupts */ + outportb(port + 1, 0x01); /* Enable interrupts */ +} + +static int serial_rcvd(int device) { + return inportb(device + 5) & 1; +} + +static char serial_recv(int device) { + while (serial_rcvd(device) == 0) ; + return inportb(device); +} + +static int serial_transmit_empty(int device) { + return inportb(device + 5) & 0x20; +} + +static void serial_send(int device, char out) { + while (serial_transmit_empty(device) == 0); + outportb(device, out); +} + +static void serial_string(char * out) { + for (uint32_t i = 0; i < strlen(out); ++i) { + serial_send(SERIAL_PORT_A, out[i]); + } +} + +static uint32_t read_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static uint32_t write_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static void open_serial(fs_node_t *node, unsigned int flags); +static void close_serial(fs_node_t *node); + +static uint32_t read_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + return read_fs(*pipe_for_port((int)node->device), offset, size, buffer); +} + +static uint32_t write_serial(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + uint32_t sent = 0; + while (sent < size) { + serial_send((int)node->device, buffer[sent]); + sent++; + } + return size; +} + +static void open_serial(fs_node_t * node, unsigned int flags) { + return; +} + +static void close_serial(fs_node_t * node) { + return; +} + +static int wait_serial(fs_node_t * node, void * process) { + return selectwait_fs(*pipe_for_port((int)node->device), process); +} +static int check_serial(fs_node_t * node) { + return selectcheck_fs(*pipe_for_port((int)node->device)); +} + +static fs_node_t * serial_device_create(int device) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->device= (void *)device; + strcpy(fnode->name, "serial"); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0660; + fnode->flags = FS_CHARDEVICE; + fnode->read = read_serial; + fnode->write = write_serial; + fnode->open = open_serial; + fnode->close = close_serial; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; /* TODO ioctls for raw serial devices */ + + fnode->selectcheck = check_serial; + fnode->selectwait = wait_serial; + + fnode->atime = now(); + fnode->mtime = fnode->atime; + fnode->ctime = fnode->atime; + + serial_enable(device); + + if (device == SERIAL_PORT_A || device == SERIAL_PORT_C) { + irq_install_handler(SERIAL_IRQ_AC, serial_handler_ac); + } else { + irq_install_handler(SERIAL_IRQ_BD, serial_handler_bd); + } + + *pipe_for_port(device) = make_pipe(128); + + return fnode; +} + +static int serial_mount_devices(void) { + + fs_node_t * ttyS0 = serial_device_create(SERIAL_PORT_A); + vfs_mount("/dev/ttyS0", ttyS0); + + fs_node_t * ttyS1 = serial_device_create(SERIAL_PORT_B); + vfs_mount("/dev/ttyS1", ttyS1); + + fs_node_t * ttyS2 = serial_device_create(SERIAL_PORT_C); + vfs_mount("/dev/ttyS2", ttyS2); + + fs_node_t * ttyS3 = serial_device_create(SERIAL_PORT_D); + vfs_mount("/dev/ttyS3", ttyS3); + + char * c; + if ((c = args_value("logtoserial"))) { + debug_file = ttyS0; + debug_level = atoi(c); + debug_print(NOTICE, "Serial logging enabled at level %d.", debug_level); + } + + + return 0; +} + +static int serial_finalize(void) { + return 0; +} + +MODULE_DEF(serial, serial_mount_devices, serial_finalize); diff --git a/modules/snd.c b/modules/snd.c new file mode 100644 index 00000000..29cd91a0 --- /dev/null +++ b/modules/snd.c @@ -0,0 +1,324 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2015 Mike Gerow + * + * Sound subsystem. + * + * Currently has the ability to mix several sound sources together. Could use + * a /dev/mixer device to allow changing of audio settings. Also could use + * the ability to change frequency and format for audio samples. Also doesn't + * really support multiple devices despite the interface suggesting it might... + */ + +#include + +#include +#include +#include +#include +#include + +/* Utility macros */ +#define N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define SND_BUF_SIZE 0x4000 + +static uint32_t snd_dsp_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer); +static int snd_dsp_ioctl(fs_node_t * node, int request, void * argp); +static void snd_dsp_open(fs_node_t * node, unsigned int flags); +static void snd_dsp_close(fs_node_t * node); + +static int snd_mixer_ioctl(fs_node_t * node, int request, void * argp); +static void snd_mixer_open(fs_node_t * node, unsigned int flags); +static void snd_mixer_close(fs_node_t * node); + +static spin_lock_t _devices_lock; + +static list_t _devices; +static fs_node_t _dsp_fnode = { + .name = "dsp", + .device = &_devices, + .mask = 0666, + .flags = FS_CHARDEVICE, + .ioctl = snd_dsp_ioctl, + .write = snd_dsp_write, + .open = snd_dsp_open, + .close = snd_dsp_close, +}; +static fs_node_t _mixer_fnode = { + .name = "mixer", + .mask = 0666, + .flags = FS_CHARDEVICE, + .ioctl = snd_mixer_ioctl, + .open = snd_mixer_open, + .close = snd_mixer_close, +}; +static spin_lock_t _buffers_lock; +static list_t _buffers; +static uint32_t _next_device_id = SND_DEVICE_MAIN; + +struct dsp_node { + ring_buffer_t * rb; + size_t samples; + size_t written; + int realtime; +}; + +int snd_register(snd_device_t * device) { + int rv = 0; + + debug_print(WARNING, "[snd] _devices lock: %d", _devices_lock); + spin_lock(_devices_lock); + device->id = _next_device_id; + _next_device_id++; + if (list_find(&_devices, device)) { + debug_print(WARNING, "[snd] attempt to register duplicate %s", device->name); + rv = -1; + goto snd_register_cleanup; + } + list_insert(&_devices, device); + debug_print(NOTICE, "[snd] %s registered", device->name); + +snd_register_cleanup: + spin_unlock(_devices_lock); + return rv; +} + +int snd_unregister(snd_device_t * device) { + int rv = 0; + + node_t * node = list_find(&_devices, device); + if (!node) { + debug_print(WARNING, "[snd] attempted to unregister %s, " + "but it was never registered", device->name); + goto snd_unregister_cleanup; + } + list_delete(&_devices, node); + debug_print(NOTICE, "[snd] %s unregistered", device->name); + +snd_unregister_cleanup: + spin_unlock(_devices_lock); + return rv; +} + +static uint32_t snd_dsp_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + if (!_devices.length) return -1; /* No sink available. */ + + struct dsp_node * dsp = node->device; + + size_t s = ring_buffer_available(dsp->rb); + size_t out; + if (size > s && dsp->realtime) { + out = ring_buffer_write(dsp->rb, s & ~0x3, buffer); + } else { + out = ring_buffer_write(dsp->rb, size, buffer); + } + dsp->written += out / 4; + + return out; +} + +static int snd_dsp_ioctl(fs_node_t * node, int request, void * argp) { + /* Potentially use this to set sample rates in the future */ + struct dsp_node * dsp = node->device; + if (request == 4) { + dsp->realtime = 1; + } else if (request == 5) { + return dsp->samples; + } + return -1; +} + +static void snd_dsp_open(fs_node_t * node, unsigned int flags) { + /* + * XXX(gerow): A process could take the memory of the entire system by opening + * too many of these... + */ + /* Allocate a buffer for the node and keep a reference for ourselves */ + + struct dsp_node * dsp = malloc(sizeof(struct dsp_node)); + dsp->rb = ring_buffer_create(SND_BUF_SIZE); + dsp->samples = 0; + dsp->written = 0; + dsp->realtime = 0; + node->device = dsp; + spin_lock(_buffers_lock); + list_insert(&_buffers, node->device); + spin_unlock(_buffers_lock); +} + +static void snd_dsp_close(fs_node_t * node) { + struct dsp_node * dsp = node->device; + spin_lock(_buffers_lock); + list_delete(&_buffers, list_find(&_buffers, dsp)); + spin_unlock(_buffers_lock); + + ring_buffer_destroy(dsp->rb); + free(dsp->rb); + free(dsp); +} + +static snd_device_t * snd_device_by_id(uint32_t device_id) { + spin_lock(_devices_lock); + snd_device_t * out = NULL; + snd_device_t * cur = NULL; + + foreach(node, &_devices) { + cur = node->value; + if (cur->id == device_id) { + out = cur; + } + } + spin_unlock(_devices_lock); + + return out; +} + +static int snd_mixer_ioctl(fs_node_t * node, int request, void * argp) { + switch (request) { + case SND_MIXER_GET_KNOBS: { + snd_knob_list_t * list = argp; + snd_device_t * device = snd_device_by_id(list->device); + if (!device) { + return -EINVAL; + } + list->num = device->num_knobs; + for (uint32_t i = 0; i < device->num_knobs; i++) { + list->ids[i] = device->knobs[i].id; + } + return 0; + } + case SND_MIXER_GET_KNOB_INFO: { + snd_knob_info_t * info = argp; + snd_device_t * device = snd_device_by_id(info->device); + if (!device) { + return -EINVAL; + } + for (uint32_t i = 0; i < device->num_knobs; i++) { + if (device->knobs[i].id == info->id) { + memcpy(info->name, device->knobs[i].name, sizeof(info->name)); + return 0; + } + } + return -EINVAL; + } + case SND_MIXER_READ_KNOB: { + snd_knob_value_t * value = argp; + snd_device_t * device = snd_device_by_id(value->device); + if (!device) { + return -EINVAL; + } + return device->mixer_read(value->id, &value->val); + } + case SND_MIXER_WRITE_KNOB: { + snd_knob_value_t * value = argp; + snd_device_t * device = snd_device_by_id(value->device); + if (!device) { + return -EINVAL; + } + return device->mixer_write(value->id, value->val); + } + default: { + return -EINVAL; + } + } +} + +static void snd_mixer_open(fs_node_t * node, unsigned int flags) { + return; +} + +static void snd_mixer_close(fs_node_t * node) { + return; +} + +int snd_request_buf(snd_device_t * device, uint32_t size, uint8_t *buffer) { + static int16_t tmp_buf[0x100]; + + memset(buffer, 0, size); + + spin_lock(_buffers_lock); + foreach(buf_node, &_buffers) { + struct dsp_node * dsp = buf_node->value; + ring_buffer_t * buf = dsp->rb; + /* ~0x3 is to ensure we don't read partial samples or just a single channel */ + size_t bytes_left = MIN(ring_buffer_unread(buf) & ~0x3, size); + int16_t * adding_ptr = (int16_t *) buffer; + while (bytes_left) { + size_t this_read_size = MIN(bytes_left, sizeof(tmp_buf)); + ring_buffer_read(buf, this_read_size, (uint8_t *)tmp_buf); + dsp->samples += this_read_size / 4; /* 16 bits, 2 channels */ + /* + * Reduce the sample by a half so that multiple sources won't immediately + * cause awful clipping. This is kind of a hack since it would probably be + * better to just use some kind of compressor. + */ + for (size_t i = 0; i < N_ELEMENTS(tmp_buf); i++) { + tmp_buf[i] /= 2; + } + for (size_t i = 0; i < this_read_size / sizeof(*adding_ptr); i++) { + adding_ptr[i] += tmp_buf[i]; + } + adding_ptr += this_read_size / sizeof(*adding_ptr); + bytes_left -= this_read_size; + } + } + spin_unlock(_buffers_lock); + + return size; +} + +static snd_device_t * snd_main_device() { + spin_lock(_devices_lock); + foreach(node, &_devices) { + spin_unlock(_devices_lock); + return node->value; + } + + spin_unlock(_devices_lock); + return NULL; +} + +#if 0 +#include +DEFINE_SHELL_FUNCTION(snd_full, "[debug] turn snd master to full") { + snd_main_device()->mixer_write(SND_KNOB_MASTER, UINT32_MAX); + + return 0; +} + +DEFINE_SHELL_FUNCTION(snd_half, "[debug] turn snd master to half") { + snd_main_device()->mixer_write(SND_KNOB_MASTER, UINT32_MAX / 2); + + return 0; +} + +DEFINE_SHELL_FUNCTION(snd_off, "[debug] turn snd master to lowest volume") { + snd_main_device()->mixer_write(SND_KNOB_MASTER, 0); + + return 0; +} +#endif + +static int init(void) { + vfs_mount("/dev/dsp", &_dsp_fnode); + vfs_mount("/dev/mixer", &_mixer_fnode); + +#if 0 + BIND_SHELL_FUNCTION(snd_full); + BIND_SHELL_FUNCTION(snd_half); + BIND_SHELL_FUNCTION(snd_off); +#endif + return 0; +} + +static int fini(void) { + /* umount? */ + return 0; +} + +MODULE_DEF(snd, init, fini); +#if 0 +MODULE_DEPENDS(debugshell); +#endif diff --git a/modules/test-write.c b/modules/test-write.c new file mode 100644 index 00000000..51c8af21 --- /dev/null +++ b/modules/test-write.c @@ -0,0 +1,53 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include + +DEFINE_SHELL_FUNCTION(testwrite, "Test write") { + + fs_node_t * f = NULL; + char * file = "/dev/hdb"; + + if (argc > 1) { + file = argv[1]; + } + + f = kopen(file, 0); + + if (!f) { + fprintf(tty, "No device: %s\n", file); + return 1; + } + + char * s = malloc(1024); + + sprintf(s, "Hello World!"); + + write_fs(f, 0, strlen(s), (uint8_t *)s); + write_fs(f, 2, strlen(s), (uint8_t *)s); + write_fs(f, 523, strlen(s), (uint8_t *)s); + + write_fs(f, 1024*12, 1024, (uint8_t *)s); + + free(s); + + return 0; +} + +static int init(void) { + BIND_SHELL_FUNCTION(testwrite); + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(testwrite, init, fini); +MODULE_DEPENDS(debugshell); diff --git a/modules/test.c b/modules/test.c new file mode 100644 index 00000000..52bfcc83 --- /dev/null +++ b/modules/test.c @@ -0,0 +1,58 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include + +#include + +extern char * special_thing; + +char test_module_string[] = "I am a char[] in the module."; +char * test_module_string_ptr = "I am a char * in the module."; + +int a_function(void) { + debug_print(WARNING, ("I am an exported function in the module.")); + return 42; +} + +DEFINE_SHELL_FUNCTION(test_mod, "A function installed by a module!") { + fprintf(tty, "Hello world!\n"); + return 0; +} + +static int hello(void) { + debug_print(NOTICE, special_thing); + a_function(); + debug_print(NOTICE, test_module_string); + debug_print(NOTICE, test_module_string_ptr); + + hashmap_t * map = hashmap_create(10); + + debug_print(NOTICE, "Inserting into hashmap..."); + + hashmap_set(map, "hello", (void *)"cake"); + debug_print(NOTICE, "getting value: %s", hashmap_get(map, "hello")); + + hashmap_free(map); + free(map); + + debug_shell_install(&shell_test_mod_desc); + BIND_SHELL_FUNCTION(test_mod); + + return 25; +} + +static int goodbye(void) { + debug_print(NOTICE, "Goodbye!"); + return 0; +} + +MODULE_DEF(test, hello, goodbye); +MODULE_DEPENDS(debugshell); + diff --git a/modules/testb.c b/modules/testb.c new file mode 100644 index 00000000..3f8bb4af --- /dev/null +++ b/modules/testb.c @@ -0,0 +1,26 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include + +extern int a_function(void); + +static int hello(void) { + debug_print(NOTICE, "Calling a_function from other module."); + a_function(); + return 0; +} + +static int goodbye(void) { + debug_print(NOTICE, "Goodbye!"); + return 0; +} + +MODULE_DEF(testb, hello, goodbye); +MODULE_DEPENDS(test); + diff --git a/modules/tmpfs.c b/modules/tmpfs.c new file mode 100644 index 00000000..99d839dd --- /dev/null +++ b/modules/tmpfs.c @@ -0,0 +1,547 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +/* 4KB */ +#define BLOCKSIZE 0x1000 + +#define TMPFS_TYPE_FILE 1 +#define TMPFS_TYPE_DIR 2 +#define TMPFS_TYPE_LINK 3 + +static char * buf_space = NULL; + +static spin_lock_t tmpfs_lock = { 0 }; +static spin_lock_t tmpfs_page_lock = { 0 }; + +struct tmpfs_dir * tmpfs_root = NULL; + +static fs_node_t * tmpfs_from_dir(struct tmpfs_dir * d); + +static struct tmpfs_file * tmpfs_file_new(char * name) { + + spin_lock(tmpfs_lock); + + struct tmpfs_file * t = malloc(sizeof(struct tmpfs_file)); + t->name = strdup(name); + t->type = TMPFS_TYPE_FILE; + t->length = 0; + t->pointers = 2; + t->block_count = 0; + t->mask = 0; + t->uid = 0; + t->gid = 0; + t->atime = now(); + t->mtime = t->atime; + t->ctime = t->atime; + t->blocks = malloc(t->pointers * sizeof(char *)); + for (size_t i = 0; i < t->pointers; ++i) { + t->blocks[i] = NULL; + } + + spin_unlock(tmpfs_lock); + return t; +} + +static void symlink_tmpfs(fs_node_t * parent, char * target, char * name) { + struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device; + debug_print(NOTICE, "Creating TMPFS file (symlink) %s in %s", name, d->name); + + spin_lock(tmpfs_lock); + foreach(f, d->files) { + struct tmpfs_file * t = (struct tmpfs_file *)f->value; + if (!strcmp(name, t->name)) { + spin_unlock(tmpfs_lock); + debug_print(WARNING, "... already exists."); + return; /* Already exists */ + } + } + spin_unlock(tmpfs_lock); + + debug_print(NOTICE, "... creating a new file (symlink)."); + struct tmpfs_file * t = tmpfs_file_new(name); + t->type = TMPFS_TYPE_LINK; + debug_print(NOTICE, "symlink target is [%s]", target); + t->target = strdup(target); + + spin_lock(tmpfs_lock); + list_insert(d->files, t); + spin_unlock(tmpfs_lock); +} + +static int readlink_tmpfs(fs_node_t * node, char * buf, size_t size) { + struct tmpfs_file * t = (struct tmpfs_file *)(node->device); + if (t->type != TMPFS_TYPE_LINK) { + debug_print(WARNING, "Not a symlink? Very confused!"); + return -1; + } + + if (size < strlen(t->target) + 1) { + debug_print(WARNING, "Requested read size was only %d, need %d.", size, strlen(t->target)+1); + memcpy(buf, t->target, size); + buf[size] = '\0'; + return size-1; + } else { + debug_print(WARNING, "Reading link target is [%s]", t->target); + memcpy(buf, t->target, strlen(t->target) + 1); + return strlen(t->target); + } +} + +static struct tmpfs_dir * tmpfs_dir_new(char * name, struct tmpfs_dir * parent) { + spin_lock(tmpfs_lock); + + struct tmpfs_dir * d = malloc(sizeof(struct tmpfs_dir)); + d->name = strdup(name); + d->type = TMPFS_TYPE_DIR; + d->mask = 0; + d->uid = 0; + d->gid = 0; + d->atime = now(); + d->mtime = d->atime; + d->ctime = d->atime; + d->files = list_create(); + + spin_unlock(tmpfs_lock); + return d; +} + +static void tmpfs_file_free(struct tmpfs_file * t) { + if (t->type == TMPFS_TYPE_LINK) { + debug_print(ERROR, "uh, what"); + free(t->target); + } + for (size_t i = 0; i < t->block_count; ++i) { + clear_frame((uintptr_t)t->blocks[i] * 0x1000); + } +} + +static void tmpfs_file_blocks_embiggen(struct tmpfs_file * t) { + t->pointers *= 2; + debug_print(INFO, "Embiggening file %s to %d blocks", t->name, t->pointers); + t->blocks = realloc(t->blocks, sizeof(char *) * t->pointers); +} + +static char * tmpfs_file_getset_block(struct tmpfs_file * t, size_t blockid, int create) { + debug_print(INFO, "Reading block %d from file %s", blockid, t->name); + + spin_lock(tmpfs_page_lock); + + if (create) { + spin_lock(tmpfs_lock); + while (blockid >= t->pointers) { + tmpfs_file_blocks_embiggen(t); + } + while (blockid >= t->block_count) { + debug_print(INFO, "Allocating block %d for file %s", blockid, t->name); + uintptr_t index = first_frame(); + set_frame(index * 0x1000); + t->blocks[t->block_count] = (char*)index; + t->block_count += 1; + } + spin_unlock(tmpfs_lock); + } else { + if (blockid >= t->block_count) { + debug_print(ERROR, "This will probably end badly."); + return NULL; + } + } + debug_print(INFO, "Using block %d->0x%x (of %d) on file %s", blockid, t->blocks[blockid], t->block_count, t->name); + + page_t * page = get_page((uintptr_t)buf_space,0,current_directory); + page->rw = 1; + page->user = 0; + page->frame = (uintptr_t)t->blocks[blockid]; + page->present = 1; + invalidate_tables_at((uintptr_t)buf_space); + + return (char *)buf_space; +} + + +static uint32_t read_tmpfs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + struct tmpfs_file * t = (struct tmpfs_file *)(node->device); + + t->atime = now(); + + uint32_t end; + if (offset + size > t->length) { + end = t->length; + } else { + end = offset + size; + } + debug_print(INFO, "reading from %d to %d", offset, end); + uint32_t start_block = offset / BLOCKSIZE; + uint32_t end_block = end / BLOCKSIZE; + uint32_t end_size = end - end_block * BLOCKSIZE; + uint32_t size_to_read = end - offset; + if (start_block == end_block && offset == end) return 0; + if (start_block == end_block) { + void *buf = tmpfs_file_getset_block(t, start_block, 0); + memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), size_to_read); + spin_unlock(tmpfs_page_lock); + return size_to_read; + } else { + uint32_t block_offset; + uint32_t blocks_read = 0; + for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { + if (block_offset == start_block) { + void *buf = tmpfs_file_getset_block(t, block_offset, 0); + memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), BLOCKSIZE - (offset % BLOCKSIZE)); + spin_unlock(tmpfs_page_lock); + } else { + void *buf = tmpfs_file_getset_block(t, block_offset, 0); + memcpy(buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), buf, BLOCKSIZE); + spin_unlock(tmpfs_page_lock); + } + } + if (end_size) { + void *buf = tmpfs_file_getset_block(t, end_block, 0); + memcpy(buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), buf, end_size); + spin_unlock(tmpfs_page_lock); + } + } + return size_to_read; +} + +static uint32_t write_tmpfs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + struct tmpfs_file * t = (struct tmpfs_file *)(node->device); + + t->atime = now(); + t->mtime = t->atime; + + uint32_t end; + if (offset + size > t->length) { + t->length = offset + size; + } + end = offset + size; + uint32_t start_block = offset / BLOCKSIZE; + uint32_t end_block = end / BLOCKSIZE; + uint32_t end_size = end - end_block * BLOCKSIZE; + uint32_t size_to_read = end - offset; + if (start_block == end_block) { + void *buf = tmpfs_file_getset_block(t, start_block, 1); + memcpy((uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), buffer, size_to_read); + spin_unlock(tmpfs_page_lock); + return size_to_read; + } else { + uint32_t block_offset; + uint32_t blocks_read = 0; + for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { + if (block_offset == start_block) { + void *buf = tmpfs_file_getset_block(t, block_offset, 1); + memcpy((uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), buffer, BLOCKSIZE - (offset % BLOCKSIZE)); + spin_unlock(tmpfs_page_lock); + } else { + void *buf = tmpfs_file_getset_block(t, block_offset, 1); + memcpy(buf, buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), BLOCKSIZE); + spin_unlock(tmpfs_page_lock); + } + } + if (end_size) { + void *buf = tmpfs_file_getset_block(t, end_block, 1); + memcpy(buf, buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), end_size); + spin_unlock(tmpfs_page_lock); + } + } + return size_to_read; +} + +static int chmod_tmpfs(fs_node_t * node, int mode) { + struct tmpfs_file * t = (struct tmpfs_file *)(node->device); + + /* XXX permissions */ + t->mask = mode; + + return 0; +} + +static int chown_tmpfs(fs_node_t * node, int uid, int gid) { + struct tmpfs_file * t = (struct tmpfs_file *)(node->device); + + debug_print(WARNING, "chown(..., %d, %d)", uid, gid); + + t->uid = uid; + t->gid = gid; + + return 0; +} + +static void open_tmpfs(fs_node_t * node, unsigned int flags) { + struct tmpfs_file * t = (struct tmpfs_file *)(node->device); + + debug_print(WARNING, "---- Opened TMPFS file %s with flags 0x%x ----", t->name, flags); + + if (flags & O_TRUNC) { + debug_print(WARNING, "Truncating file %s", t->name); + for (size_t i = 0; i < t->block_count; ++i) { + clear_frame((uintptr_t)t->blocks[i] * 0x1000); + t->blocks[i] = 0; + } + t->block_count = 0; + t->length = 0; + } + + return; +} + +static fs_node_t * tmpfs_from_file(struct tmpfs_file * t) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, t->name); + fnode->device = t; + fnode->mask = t->mask; + fnode->uid = t->uid; + fnode->gid = t->gid; + fnode->atime = t->atime; + fnode->ctime = t->ctime; + fnode->mtime = t->mtime; + fnode->flags = FS_FILE; + fnode->read = read_tmpfs; + fnode->write = write_tmpfs; + fnode->open = open_tmpfs; + fnode->close = NULL; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->chmod = chmod_tmpfs; + fnode->chown = chown_tmpfs; + fnode->length = t->length; + fnode->nlink = 1; + return fnode; +} + +static fs_node_t * tmpfs_from_link(struct tmpfs_file * t) { + fs_node_t * fnode = tmpfs_from_file(t); + fnode->flags |= FS_SYMLINK; + fnode->readlink = readlink_tmpfs; + fnode->read = NULL; + fnode->write = NULL; + fnode->create = NULL; + fnode->mkdir = NULL; + fnode->readdir = NULL; + fnode->finddir = NULL; + return fnode; +} + +static struct dirent * readdir_tmpfs(fs_node_t *node, uint32_t index) { + struct tmpfs_dir * d = (struct tmpfs_dir *)node->device; + uint32_t i = 0; + + debug_print(NOTICE, "tmpfs - readdir id=%d", index); + + if (index == 0) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, "."); + return out; + } + + if (index == 1) { + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = 0; + strcpy(out->name, ".."); + return out; + } + + index -= 2; + + if (index >= d->files->length) return NULL; + + foreach(f, d->files) { + if (i == index) { + struct tmpfs_file * t = (struct tmpfs_file *)f->value; + struct dirent * out = malloc(sizeof(struct dirent)); + memset(out, 0x00, sizeof(struct dirent)); + out->ino = (uint32_t)t; + strcpy(out->name, t->name); + return out; + } else { + ++i; + } + } + return NULL; +} + +static fs_node_t * finddir_tmpfs(fs_node_t * node, char * name) { + if (!name) return NULL; + + struct tmpfs_dir * d = (struct tmpfs_dir *)node->device; + + spin_lock(tmpfs_lock); + + foreach(f, d->files) { + struct tmpfs_file * t = (struct tmpfs_file *)f->value; + if (!strcmp(name, t->name)) { + spin_unlock(tmpfs_lock); + switch (t->type) { + case TMPFS_TYPE_FILE: + return tmpfs_from_file(t); + case TMPFS_TYPE_LINK: + return tmpfs_from_link(t); + case TMPFS_TYPE_DIR: + return tmpfs_from_dir((struct tmpfs_dir *)t); + } + return NULL; + } + } + + spin_unlock(tmpfs_lock); + + return NULL; +} + +static void unlink_tmpfs(fs_node_t * node, char * name) { + struct tmpfs_dir * d = (struct tmpfs_dir *)node->device; + int i = -1, j = 0; + spin_lock(tmpfs_lock); + + foreach(f, d->files) { + struct tmpfs_file * t = (struct tmpfs_file *)f->value; + if (!strcmp(name, t->name)) { + tmpfs_file_free(t); + free(t); + i = j; + break; + } + j++; + } + + if (i >= 0) { + list_remove(d->files, i); + } + + spin_unlock(tmpfs_lock); + return; +} + +static void create_tmpfs(fs_node_t *parent, char *name, uint16_t permission) { + if (!name) return; + + struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device; + debug_print(NOTICE, "Creating TMPFS file %s in %s", name, d->name); + + spin_lock(tmpfs_lock); + foreach(f, d->files) { + struct tmpfs_file * t = (struct tmpfs_file *)f->value; + if (!strcmp(name, t->name)) { + spin_unlock(tmpfs_lock); + debug_print(WARNING, "... already exists."); + return; /* Already exists */ + } + } + spin_unlock(tmpfs_lock); + + debug_print(NOTICE, "... creating a new file."); + struct tmpfs_file * t = tmpfs_file_new(name); + t->mask = permission; + t->uid = current_process->user; + t->gid = current_process->user; + + spin_lock(tmpfs_lock); + list_insert(d->files, t); + spin_unlock(tmpfs_lock); +} + +static void mkdir_tmpfs(fs_node_t * parent, char * name, uint16_t permission) { + if (!name) return; + + struct tmpfs_dir * d = (struct tmpfs_dir *)parent->device; + debug_print(NOTICE, "Creating TMPFS directory %s (in %s)", name, d->name); + + spin_lock(tmpfs_lock); + foreach(f, d->files) { + struct tmpfs_file * t = (struct tmpfs_file *)f->value; + if (!strcmp(name, t->name)) { + spin_unlock(tmpfs_lock); + debug_print(WARNING, "... already exists."); + return; /* Already exists */ + } + } + spin_unlock(tmpfs_lock); + + debug_print(NOTICE, "... creating a new directory."); + struct tmpfs_dir * out = tmpfs_dir_new(name, d); + out->mask = permission; + out->uid = current_process->user; + out->gid = current_process->user; + + spin_lock(tmpfs_lock); + list_insert(d->files, out); + spin_unlock(tmpfs_lock); +} + +static fs_node_t * tmpfs_from_dir(struct tmpfs_dir * d) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, "tmp"); + fnode->mask = d->mask; + fnode->uid = d->uid; + fnode->gid = d->gid; + fnode->device = d; + fnode->atime = d->atime; + fnode->mtime = d->mtime; + fnode->ctime = d->ctime; + fnode->flags = FS_DIRECTORY; + fnode->read = NULL; + fnode->write = NULL; + fnode->open = NULL; + fnode->close = NULL; + fnode->readdir = readdir_tmpfs; + fnode->finddir = finddir_tmpfs; + fnode->create = create_tmpfs; + fnode->unlink = unlink_tmpfs; + fnode->mkdir = mkdir_tmpfs; + fnode->nlink = 1; /* should be "number of children that are directories + 1" */ + fnode->symlink = symlink_tmpfs; + + fnode->chown = chown_tmpfs; + fnode->chmod = chmod_tmpfs; + + return fnode; +} + +fs_node_t * tmpfs_create(char * name) { + tmpfs_root = tmpfs_dir_new(name, NULL); + tmpfs_root->mask = 0777; + tmpfs_root->uid = 0; + tmpfs_root->gid = 0; + + return tmpfs_from_dir(tmpfs_root); +} + +fs_node_t * tmpfs_mount(char * device, char * mount_path) { + fs_node_t * fs = tmpfs_create(device); + return fs; +} + +static int tmpfs_initialize(void) { + + buf_space = (void*)kvmalloc(BLOCKSIZE); + + vfs_mount("/tmp", tmpfs_create("tmp")); + vfs_mount("/var", tmpfs_create("var")); + + vfs_register("tmpfs", tmpfs_mount); + + return 0; +} +static int tmpfs_finalize(void) { + return 0; +} + +MODULE_DEF(tmpfs, tmpfs_initialize, tmpfs_finalize); diff --git a/modules/usbuhci.c b/modules/usbuhci.c new file mode 100644 index 00000000..d9873224 --- /dev/null +++ b/modules/usbuhci.c @@ -0,0 +1,50 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include +#include + +static uint32_t hub_device = 0; + +static void find_usb_device(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) { + if (pci_find_type(device) == 0xc03) { + int prog_if = (int)pci_read_field(device, PCI_PROG_IF, 1); + if (prog_if == 0) { + *((uint32_t *)extra)= device; + } + } +} + +DEFINE_SHELL_FUNCTION(usb, "Enumerate USB devices (UHCI)") { + + pci_scan(&find_usb_device, -1, &hub_device); + + if (!hub_device) { + fprintf(tty, "Failed to locate a UHCI controller.\n"); + return 1; + } + + fprintf(tty, "Located UHCI controller: %2x:%2x.%d\n", + (int)pci_extract_bus (hub_device), + (int)pci_extract_slot(hub_device), + (int)pci_extract_func(hub_device)); + + return 0; +} + +static int install(void) { + BIND_SHELL_FUNCTION(usb); + return 0; +} + +static int uninstall(void) { + return 0; +} + +MODULE_DEF(usbuhci, install, uninstall); +MODULE_DEPENDS(debugshell); diff --git a/modules/vboxguest.c b/modules/vboxguest.c new file mode 100644 index 00000000..4316fe27 --- /dev/null +++ b/modules/vboxguest.c @@ -0,0 +1,270 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016 Kevin Lange + * + * VirtualBox Guest Additions driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VBOX_VENDOR_ID 0x80EE +#define VBOX_DEVICE_ID 0xCAFE + +static void vbox_scan_pci(uint32_t device, uint16_t v, uint16_t d, void * extra) { + if (v == VBOX_VENDOR_ID && d == VBOX_DEVICE_ID) { + *((uint32_t *)extra) = device; + } +} + +#define VMMDEV_VERSION 0x00010003 +#define VBOX_REQUEST_HEADER_VERSION 0x10001 +struct vbox_header { + uint32_t size; + uint32_t version; + uint32_t requestType; + int32_t rc; + uint32_t reserved1; + uint32_t reserved2; +}; + +struct vbox_guest_info { + struct vbox_header header; + uint32_t version; + uint32_t ostype; +}; + +struct vbox_guest_caps { + struct vbox_header header; + uint32_t caps; +}; + +struct vbox_ack_events { + struct vbox_header header; + uint32_t events; +}; + +struct vbox_display_change { + struct vbox_header header; + uint32_t xres; + uint32_t yres; + uint32_t bpp; + uint32_t eventack; +}; + +struct vbox_mouse { + struct vbox_header header; + uint32_t features; + int32_t x; + int32_t y; +}; + + +#define EARLY_LOG_DEVICE 0x504 +static uint32_t _vbox_write(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + for (unsigned int i = 0; i < size; ++i) { + outportb(EARLY_LOG_DEVICE, buffer[i]); + } + return size; +} +static fs_node_t vb = { .write = &_vbox_write }; + +static uint32_t vbox_device = 0; +static uint32_t vbox_port = 0x0; +static int vbox_irq = 0; + +static struct vbox_ack_events * vbox_irq_ack; +static uint32_t vbox_phys_ack; +static struct vbox_display_change * vbox_disp; +static uint32_t vbox_phys_disp; +static struct vbox_mouse * vbox_m; +static uint32_t vbox_phys_mouse; +static struct vbox_mouse * vbox_mg; +static uint32_t vbox_phys_mouse_get; +static uint32_t * vbox_vmmdev = 0; + +static fs_node_t * mouse_pipe; + +#define PACKETS_IN_PIPE 1024 +#define DISCARD_POINT 32 + +static int vbox_irq_handler(struct regs *r) { + outportl(vbox_port, vbox_phys_disp); + outportl(vbox_port, vbox_phys_mouse_get); + outportl(vbox_port, vbox_phys_ack); + irq_ack(vbox_irq); + + if (lfb_vid_memory && lfb_resolution_x && lfb_resolution_y && vbox_mg->x && vbox_mg->y) { + unsigned int x = ((unsigned int)vbox_mg->x * lfb_resolution_x) / 0xFFFF; + unsigned int y = ((unsigned int)vbox_mg->y * lfb_resolution_y) / 0xFFFF; + + mouse_device_packet_t packet; + packet.magic = MOUSE_MAGIC; + packet.x_difference = x; + packet.y_difference = y; + packet.buttons = 0; + + mouse_device_packet_t bitbucket; + while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { + read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); + } + write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); + } + + + if (lfb_resolution_x && vbox_disp->xres && (vbox_disp->xres != lfb_resolution_x || vbox_disp->yres != lfb_resolution_y)) { + + lfb_set_resolution(vbox_disp->xres, vbox_disp->yres); + } + return 1; +} + +void vbox_set_log(void) { + debug_file = &vb; +} + +#define VBOX_MOUSE_ON (1 << 0) | (1 << 4) +#define VBOX_MOUSE_OFF (0) + +static void mouse_on_off(unsigned int status) { + vbox_m->header.size = sizeof(struct vbox_mouse); + vbox_m->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_m->header.requestType = 2; + vbox_m->header.rc = 0; + vbox_m->header.reserved1 = 0; + vbox_m->header.reserved2 = 0; + vbox_m->features = status; + vbox_m->x = 0; + vbox_m->y = 0; + outportl(vbox_port, vbox_phys_mouse); +} + +static int ioctl_mouse(fs_node_t * node, int request, void * argp) { + if (request == 1) { + /* Disable */ + mouse_on_off(VBOX_MOUSE_OFF); + return 0; + } + if (request == 2) { + /* Enable */ + mouse_on_off(VBOX_MOUSE_ON); + return 0; + } + return -1; +} + +static int vbox_check(void) { + pci_scan(vbox_scan_pci, -1, &vbox_device); + + if (vbox_device) { + fprintf(&vb, "VirtualBox host detected, switching log to VirtualBox.\n"); + + if (args_present("vboxdebug")) { + vbox_set_log(); + } + + uintptr_t t = pci_read_field(vbox_device, PCI_BAR0, 4); + if (t > 0) { + vbox_port = (t & 0xFFFFFFF0); + } + + mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); + mouse_pipe->flags = FS_CHARDEVICE; + mouse_pipe->ioctl = ioctl_mouse; + + vfs_mount("/dev/absmouse", mouse_pipe); + + vbox_irq = pci_read_field(vbox_device, PCI_INTERRUPT_LINE, 1); + debug_print(WARNING, "(vbox) device IRQ is set to %d\n", vbox_irq); + irq_install_handler(vbox_irq, vbox_irq_handler); + + uint32_t vbox_phys = 0; + struct vbox_guest_info * packet = (void*)kvmalloc_p(0x1000, &vbox_phys); + packet->header.size = sizeof(struct vbox_guest_info); + packet->header.version = VBOX_REQUEST_HEADER_VERSION; + packet->header.requestType = 50; + packet->header.rc = 0; + packet->header.reserved1 = 0; + packet->header.reserved2 = 0; + packet->version = VMMDEV_VERSION; + packet->ostype = 0; + + outportl(vbox_port, vbox_phys); + + struct vbox_guest_caps * caps = (void*)kvmalloc_p(0x1000, &vbox_phys); + caps->header.size = sizeof(struct vbox_guest_caps); + caps->header.version = VBOX_REQUEST_HEADER_VERSION; + caps->header.requestType = 55; + caps->header.rc = 0; + caps->header.reserved1 = 0; + caps->header.reserved2 = 0; + caps->caps = 1 << 2; + outportl(vbox_port, vbox_phys); + + vbox_irq_ack = (void*)kvmalloc_p(0x1000, &vbox_phys_ack); + vbox_irq_ack->header.size = sizeof(struct vbox_ack_events); + vbox_irq_ack->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_irq_ack->header.requestType = 41; + vbox_irq_ack->header.rc = 0; + vbox_irq_ack->header.reserved1 = 0; + vbox_irq_ack->header.reserved2 = 0; + vbox_irq_ack->events = 0; + + vbox_disp = (void*)kvmalloc_p(0x1000, &vbox_phys_disp); + vbox_disp->header.size = sizeof(struct vbox_display_change); + vbox_disp->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_disp->header.requestType = 51; + vbox_disp->header.rc = 0; + vbox_disp->header.reserved1 = 0; + vbox_disp->header.reserved2 = 0; + vbox_disp->xres = 0; + vbox_disp->yres = 0; + vbox_disp->bpp = 0; + vbox_disp->eventack = 1; + + vbox_m = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse); + mouse_on_off(VBOX_MOUSE_ON); + + /* For use with later receives */ + vbox_mg = (void*)kvmalloc_p(0x1000, &vbox_phys_mouse_get); + vbox_mg->header.size = sizeof(struct vbox_mouse); + vbox_mg->header.version = VBOX_REQUEST_HEADER_VERSION; + vbox_mg->header.requestType = 1; + vbox_mg->header.rc = 0; + vbox_mg->header.reserved1 = 0; + vbox_mg->header.reserved2 = 0; + + /* device memory region mapping? */ + { + uintptr_t t = pci_read_field(vbox_device, PCI_BAR1, 4); + if (t > 0) { + vbox_vmmdev = (void *)(t & 0xFFFFFFF0); + } + uintptr_t fb_offset = (uintptr_t)vbox_vmmdev; + for (uintptr_t i = fb_offset; i <= fb_offset + 0x2000; i += 0x1000) { + dma_frame(get_page(i, 1, kernel_directory), 0, 1, i); + } + } + + vbox_vmmdev[3] = 0xFFFFFFFF; /* Enable all for now */ + } + + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(vboxguest, vbox_check, fini); +MODULE_DEPENDS(lfbvideo); diff --git a/modules/vgadbg.c b/modules/vgadbg.c new file mode 100644 index 00000000..ef5445cd --- /dev/null +++ b/modules/vgadbg.c @@ -0,0 +1,208 @@ +#include +#include +#include + +#include + +static unsigned short * textmemptr = (unsigned short *)0xB8000; +static void placech(unsigned char c, int x, int y, int attr) { + unsigned short *where; + unsigned att = attr << 8; + where = textmemptr + (y * 80 + x); + *where = c | att; +} + +static char vga_to_ansi[] = { + 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 +}; + +static int fg = 0x07; +static int bg = 0x10; +static int cur_x = 0; +static int cur_y = 0; + +static int write_string(char * s) { + int written = 0; + while (*s) { + switch (*s) { + case '\n': + cur_x = 0; + cur_y++; + break; + case '\b': + if (cur_x > 0) cur_x--; + placech(' ', cur_x, cur_y, (vga_to_ansi[fg] & 0xF) | (vga_to_ansi[bg] << 4)); + break; + default: + placech(*s, cur_x, cur_y, (vga_to_ansi[fg] & 0xF) | (vga_to_ansi[bg] << 4)); + cur_x++; + break; + } + if (cur_x == 80) { + cur_x = 0; + cur_y++; + } + if (cur_y == 25) { + memmove(textmemptr, (textmemptr + 80), sizeof(unsigned short) * 80 * 24); + memset(textmemptr + 80 * 24, 0x00, 80 * sizeof(unsigned short)); + cur_y = 24; + } + s++; + written++; + } + return written; +} + +static void reset(void) { + fg = 0x07; + bg = 0x10; +} + +static void list_files(char * directory) { + fs_node_t * wd = kopen(directory, 0); + uint32_t index = 0; + struct dirent * kentry = readdir_fs(wd, index); + while (kentry) { + write_string(kentry->name); + write_string("\n"); + free(kentry); + + index++; + kentry = readdir_fs(wd, index); + } + close_fs(wd); +} + +static void debug_ata_wait(void) { + inportb(0x1F0 + ATA_REG_ALTSTATUS); + inportb(0x1F0 + ATA_REG_ALTSTATUS); + inportb(0x1F0 + ATA_REG_ALTSTATUS); + inportb(0x1F0 + ATA_REG_ALTSTATUS); +} + +static void debug_ata_primary(void) { + /* Reset */ + char tmp[100]; + outportb(0x3F6, 0x04); + + debug_ata_wait(); + + outportb(0x3F6, 0x00); + + debug_ata_wait(); + + outportb(0x1F0 + ATA_REG_HDDEVSEL, 0xA0); + + debug_ata_wait(); + + /* Wait on device */ + int status; + int i = 0; + while ((status = inportb(0x1F0 + ATA_REG_STATUS)) & ATA_SR_BSY) i++; + + sprintf(tmp, "Waited on status %d times\n", i); + write_string(tmp); + + unsigned char cl = inportb(0x1F0 + ATA_REG_LBA1); /* CYL_LO */ + unsigned char ch = inportb(0x1F0 + ATA_REG_LBA2); /* CYL_HI */ + + if (cl == 0xD0) { + write_string("Waiting some more...\n"); + inportb(0x1F0 + ATA_REG_ALTSTATUS); + inportb(0x1F0 + ATA_REG_ALTSTATUS); + cl = inportb(0x1F0 + ATA_REG_LBA1); /* CYL_LO */ + ch = inportb(0x1F0 + ATA_REG_LBA2); /* CYL_HI */ + } + sprintf(tmp, "ATA Primary 0x%2x 0x%2x\n", cl, ch); + write_string(tmp); + + /* Now check partitions */ + mbr_t mbr; + + fs_node_t * f = kopen("/dev/hda", 0); + + if (!f) { + write_string("Couldn't open /dev/hda\n"); + + } else { + + read_fs(f, 0, 512, (uint8_t *)&mbr); + + sprintf(tmp, "signature[0] = 0x%2x\n", mbr.signature[0]); + write_string(tmp); + sprintf(tmp, "signature[1] = 0x%2x\n", mbr.signature[1]); + write_string(tmp); + + write_string("Partitions:\n"); + + for (int i = 0; i < 4; ++i) { + if (mbr.partitions[i].status & 0x80) { + sprintf(tmp, "Partition #%d: @%d+%d\n", i+1, mbr.partitions[i].lba_first_sector, mbr.partitions[i].sector_count); + write_string(tmp); + } else { + sprintf(tmp, "Partition #%d: inactive\n", i+1); + write_string(tmp); + } + } + + } + +} + +static void tasklet(void * data, char * name) { + + write_string("Tasklet created, sleeping... _"); + + for (int i = 5; i > 0; i--) { + char tmp[3]; + sprintf(tmp, "\b%d", i); + write_string(tmp); + unsigned long s, ss; + relative_time(1, 0, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + } + + write_string("\bDone.\nReady to go.\n"); + + write_string("Here's /dev:\n"); + fg = 6; + list_files("/dev"); + reset(); + + write_string("Now let's debug the primary PATA drive:\n"); + debug_ata_primary(); + + reset(); + write_string("Here's /\n"); + fg = 6; + list_files("/"); + reset(); + + write_string("Here's /home"); + fg = 6; + list_files("/home"); + reset(); + +} + +static int vgadbg_init(void) { + + memset(textmemptr, 0x00, sizeof(unsigned short) * 80 * 25); + + write_string("VGA Text-Mode Debugger\n"); + write_string(" If you're seeing this, module loading completed successfully.\n"); + write_string(" We'll now do some checks to see what may be wrong with the system.\n"); + write_string("\n"); + + create_kernel_tasklet(tasklet, "[[vgadbg]]", NULL); + + return 0; +} + +static int vgadbg_fini(void) { + return 0; +} + +MODULE_DEF(vgadbg, vgadbg_init, vgadbg_fini); diff --git a/modules/vgalog.c b/modules/vgalog.c new file mode 100644 index 00000000..ba56ff7d --- /dev/null +++ b/modules/vgalog.c @@ -0,0 +1,176 @@ +#include +#include +#include + +#include + +#include "../lib/termemu.c" + +static unsigned short * textmemptr = (unsigned short *)0xB8000; +static void placech(unsigned char c, int x, int y, int attr) { + unsigned short *where; + unsigned att = attr << 8; + where = textmemptr + (y * 80 + x); + *where = c | att; +} + +static char vga_to_ansi[] = { + 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 +}; + +static int current_fg = 0x07; +static int current_bg = 0x10; +static int cur_x = 0; +static int cur_y = 0; + +term_state_t * ansi_state = NULL; + +static int write_string(char * s) { + int written = 0; + while (*s) { + switch (*s) { + case '\n': + cur_x = 0; + cur_y++; + break; + case '\b': + if (cur_x > 0) cur_x--; + placech(' ', cur_x, cur_y, (vga_to_ansi[current_fg] & 0xF) | (vga_to_ansi[current_bg] << 4)); + break; + default: + placech(*s, cur_x, cur_y, (vga_to_ansi[current_fg] & 0xF) | (vga_to_ansi[current_bg] << 4)); + cur_x++; + break; + } + if (cur_x == 80) { + cur_x = 0; + cur_y++; + } + if (cur_y == 25) { + memmove(textmemptr, (textmemptr + 80), sizeof(unsigned short) * 80 * 24); + memset(textmemptr + 80 * 24, 0x00, 80 * sizeof(unsigned short)); + cur_y = 24; + } + s++; + written++; + } + return written; +} + +static void term_write(char c) { + char foo[] = {c,0}; + write_string(foo); +} + +static uint32_t vga_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t *buffer) { + /* XXX do some terminal processing like we did in the old days */ + size_t i = 0; + while (*buffer && i < size) { + ansi_put(ansi_state, *buffer); + buffer++; + i++; + } + return i; +} + +static fs_node_t _vga_fnode = { + .name = "vga_log", + .write = vga_write, +}; + +static void term_scroll(int how_much) { + for (int i = 0; i < how_much; ++i) { + memmove(textmemptr, (textmemptr + 80), sizeof(unsigned short) * 80 * 24); + memset(textmemptr + 80 * 24, 0x00, 80 * sizeof(unsigned short)); + } +} + +static void term_set_cell(int x, int y, uint32_t c) { + placech(c, x, y, (vga_to_ansi[current_fg] & 0xF) | (vga_to_ansi[current_bg] << 4)); +} + +static void term_set_csr(int x, int y) { + cur_x = x; + cur_y = y; +} + +static int term_get_csr_x() { + return cur_x; +} + +static int term_get_csr_y() { + return cur_y; +} + +static void term_set_csr_show(int on) { + return; +} + +static void term_set_colors(uint32_t fg, uint32_t bg) { + current_fg = fg; + current_bg = bg; +} + +static void term_redraw_cursor() { + return; +} + +static void input_buffer_stuff(char * str) { + return; +} + +static void set_term_font_size(float s) { + /* Do nothing */ +} + +static void set_title(char * c) { + /* Do nothing */ +} + +static void term_clear(int i) { + memset(textmemptr, 0x00, sizeof(unsigned short) * 80 * 25); +} + +int unsupported_int(void) { return 0; } +void unsupported(int x, int y, char * data) { } + +term_callbacks_t term_callbacks = { + term_write, + term_set_colors, + term_set_csr, + term_get_csr_x, + term_get_csr_y, + term_set_cell, + term_clear, + term_scroll, + term_redraw_cursor, + input_buffer_stuff, + set_term_font_size, + set_title, + unsupported, + unsupported_int, + unsupported_int, + term_set_csr_show, +}; + + +static int vgadbg_init(void) { + + memset(textmemptr, 0x00, sizeof(unsigned short) * 80 * 25); + + ansi_state = ansi_init(ansi_state, 80, 25, &term_callbacks); + + debug_file = &_vga_fnode; + debug_level = 1; + + write_string("VGA Debug Logging is enabled.\n"); + + return 0; +} + +static int vgadbg_fini(void) { + return 0; +} + +MODULE_DEF(vgalog, vgadbg_init, vgadbg_fini); diff --git a/modules/vidset.c b/modules/vidset.c new file mode 100644 index 00000000..5660998a --- /dev/null +++ b/modules/vidset.c @@ -0,0 +1,43 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2016 Kevin Lange + * + * Module to provide a debug shell command to set display mode. + */ +#include +#include +#include +#include +#include + +#include +#include + +DEFINE_SHELL_FUNCTION(set_mode, "Set display mode") { + if (argc < 3) { + fprintf(tty, "set_mode \n"); + return 1; + } + int x = atoi(argv[1]); + int y = atoi(argv[2]); + fprintf(tty, "Setting mode to %dx%d.\n", x, y); + lfb_set_resolution(x,y); + return 0; +} + +static int hello(void) { + BIND_SHELL_FUNCTION(set_mode); + + return 0; +} + +static int goodbye(void) { + return 0; +} + +MODULE_DEF(vidset, hello, goodbye); +MODULE_DEPENDS(debugshell); +MODULE_DEPENDS(lfbvideo); + + diff --git a/modules/vmware.c b/modules/vmware.c new file mode 100644 index 00000000..e489b111 --- /dev/null +++ b/modules/vmware.c @@ -0,0 +1,291 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2017 Kevin Lange + * + * VMWare absolute mouse driver. + * + * This device is also available by default in QEMU. + * + * Toggle off / back on with ioctl 1 and 2 respectively to /dev/vmmouse. + * + * Actually supports mouse buttons, unlike the one in VirtualBox. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VMWARE_MAGIC 0x564D5868 +#define VMWARE_PORT 0x5658 + +#define PACKETS_IN_PIPE 1024 +#define DISCARD_POINT 32 + +/* -Wpedantic complains about unnamed unions */ +#pragma GCC diagnostic ignored "-Wpedantic" + +extern void (*ps2_mouse_alternate)(void); /* modules/mouse.c */ + +static fs_node_t * mouse_pipe; + +typedef struct { + union { + uint32_t ax; + uint32_t magic; + }; + union { + uint32_t bx; + size_t size; + }; + union { + uint32_t cx; + uint16_t command; + }; + union { + uint32_t dx; + uint16_t port; + }; + uint32_t si; + uint32_t di; +} vmware_cmd; + +static void vmware_io(vmware_cmd * cmd) { + uint32_t dummy; + + /* Now how's THAT for a VM backdoor... */ + + asm volatile( + "pushl %%ebx\n" + "pushl %%eax\n" + "movl 20(%%eax), %%edi\n" /* Load data into registers */ + "movl 16(%%eax), %%esi\n" + "movl 12(%%eax), %%edx\n" + "movl 8(%%eax), %%ecx\n" + "movl 4(%%eax), %%ebx\n" + "movl (%%eax), %%eax\n" + "inl %%dx, %%eax\n" /* Then trip a magic i/o port */ + "xchgl %%eax, (%%esp)\n" + "movl %%edi, 20(%%eax)\n" /* Data also comes back out by registers */ + "movl %%esi, 16(%%eax)\n" + "movl %%edx, 12(%%eax)\n" + "movl %%ecx, 8(%%eax)\n" + "movl %%ebx, 4(%%eax)\n" + "popl (%%eax)\n" + "popl %%ebx\n" + : "=a"(dummy) + : "0"(cmd) + : "ecx", "edx", "esi", "edi", "memory" /* And vmware / qemu could trash anything they desire... */ + ); +} + +static void vmware_send(vmware_cmd * cmd) { + cmd->magic = VMWARE_MAGIC; + cmd->port = VMWARE_PORT; + + vmware_io(cmd); +} + +static void mouse_on(void) { + vmware_cmd cmd; + + /* Enable */ + cmd.bx = 0x45414552; + cmd.command = 41; + vmware_send(&cmd); + + /* Status */ + cmd.bx = 0; + cmd.command = 40; + vmware_send(&cmd); + + /* Read data (1) */ + cmd.bx = 1; + cmd.command = 39; + vmware_send(&cmd); + + debug_print(WARNING, "Enabled with version ID %x", cmd.ax); +} + +static void mouse_off(void) { + /* Disable the absolute mouse */ + vmware_cmd cmd; + cmd.bx = 0xf5; + cmd.command = 41; + vmware_send(&cmd); +} + +static void mouse_absolute(void) { + /* + * Set the mouse to absolute. + * + * You can also set a relative mode, but there's not + * a lot of use in that as disabling the device just + * falls back to the PS/2 (or USB, I guess) device anyway, + * so instead of using that we just... turn it off. + */ + + vmware_cmd cmd; + cmd.bx = 0x53424152; /* request absolute */ + cmd.command = 41; /* request for abs/rel */ + vmware_send(&cmd); +} + +volatile int8_t vmware_mouse_byte; + +static void vmware_mouse(void) { + /* unused, but we need to read the fake mouse event bytes from the PS/2 device. */ + vmware_mouse_byte = inportb(0x60); + + /* Read status byte. */ + vmware_cmd cmd; + cmd.bx = 0; + cmd.command = 40; + vmware_send(&cmd); + + if (cmd.ax == 0xffff0000) { + /* Device error; turn it off and back on again. */ + mouse_off(); + mouse_on(); + mouse_absolute(); + return; + } + + int words = cmd.ax & 0xFFFF; + + if (!words || words % 4) { + /* If we don't have data, or for some reason data isn't a multiple of 4... bail */ + return; + } + + /* Read 4 bytes of data */ + cmd.bx = 4; /* how many */ + cmd.command = 39; /* read */ + vmware_send(&cmd); + + /* + * I guess the flags tell you if this was relative or absolute, so if we + * actually used the relative mode, we'd want to check that, but... + */ + int flags = (cmd.ax & 0xFFFF0000) >> 16; + int buttons = (cmd.ax & 0x0000FFFF); + + debug_print(INFO, "flags=%4x buttons=%4x", flags, buttons); + debug_print(INFO, "x=%x y=%x z=%x", cmd.bx, cmd.cx, cmd.dx); + + if (lfb_vid_memory && lfb_resolution_x && lfb_resolution_y) { + /* + * Just like the virtualbox stuff, this is based on a mapping + * to the display resolution, independently scaled in + * each dimension... + */ + unsigned int x = ((unsigned int)cmd.bx * lfb_resolution_x) / 0xFFFF; + unsigned int y = ((unsigned int)cmd.cx * lfb_resolution_y) / 0xFFFF; + + mouse_device_packet_t packet; + packet.magic = MOUSE_MAGIC; + packet.x_difference = x; + packet.y_difference = y; + packet.buttons = 0; + + /* The particular bits for the buttons seem weird, but okay... */ + if (buttons & 0x20) { + packet.buttons |= LEFT_CLICK; + } + if (buttons & 0x10) { + packet.buttons |= RIGHT_CLICK; + } + if (buttons & 0x08) { + packet.buttons |= MIDDLE_CLICK; + } + + /* dx = z = scroll amount */ + if ((int8_t)cmd.dx > 0) { + packet.buttons |= MOUSE_SCROLL_DOWN; + } else if ((int8_t)cmd.dx < 0) { + packet.buttons |= MOUSE_SCROLL_UP; + } + + mouse_device_packet_t bitbucket; + while (pipe_size(mouse_pipe) > (int)(DISCARD_POINT * sizeof(packet))) { + read_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&bitbucket); + } + write_fs(mouse_pipe, 0, sizeof(packet), (uint8_t *)&packet); + } + +} + +static int detect_device(void) { + vmware_cmd cmd; + + /* read version */ + cmd.bx = ~VMWARE_MAGIC; + cmd.command = 10; + vmware_send(&cmd); + + if (cmd.bx != VMWARE_MAGIC || cmd.ax == 0xFFFFFFFF) { + /* Not a vmware device... */ + return 0; + } + + /* Good to go! */ + return 1; +} + +static int ioctl_mouse(fs_node_t * node, int request, void * argp) { + if (request == 1) { + /* Disable */ + mouse_off(); + ps2_mouse_alternate = NULL; + return 0; + } + if (request == 2) { + /* Enable */ + ps2_mouse_alternate = vmware_mouse; + mouse_on(); + mouse_absolute(); + return 0; + } + return -1; +} + +static int init(void) { + if (detect_device()) { + + mouse_pipe = make_pipe(sizeof(mouse_device_packet_t) * PACKETS_IN_PIPE); + mouse_pipe->flags = FS_CHARDEVICE; + + vfs_mount("/dev/vmmouse", mouse_pipe); + + mouse_pipe->flags = FS_CHARDEVICE; + mouse_pipe->ioctl = ioctl_mouse; + + /* + * We have a hack in the PS/2 mouse driver that lets us + * take over for the normal mouse driver and essential + * intercept the interrputs when they are valid. + */ + ps2_mouse_alternate = vmware_mouse; + + mouse_on(); + mouse_absolute(); + + } + + return 0; +} + +static int fini(void) { + return 0; +} + +MODULE_DEF(vmmware, init, fini); +MODULE_DEPENDS(ps2mouse); /* For ps2_mouse_alternate */ +MODULE_DEPENDS(lfbvideo); /* For lfb resolution */ diff --git a/modules/xtest.c b/modules/xtest.c new file mode 100644 index 00000000..ea66bb94 --- /dev/null +++ b/modules/xtest.c @@ -0,0 +1,46 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + */ +#include +#include +#include +#include + +#include + +static void xtest_a(void * data, char * name) { + fs_node_t * tty = data; + + fprintf(tty, "[%s] Hello world.\n", name); + + while (1) { + fprintf(tty, "[%s] Ping.\n", name); + unsigned long s, ss; + relative_time(1, 0, &s, &ss); + sleep_until((process_t *)current_process, s, ss); + switch_task(0); + } +} + +static int hello(void) { + fs_node_t * tty = kopen("/dev/ttyS0", 0); + + fprintf(tty, "[xtest] Starting background thread...\n"); + create_kernel_tasklet(xtest_a, "xtest-a", (void *)tty); + + fprintf(tty, "[xtest] Enabling logging directly to serial...\n"); + debug_file = tty; + debug_level = 1; + + return 0; +} + +static int goodbye(void) { + return 0; +} + +MODULE_DEF(xtest, hello, goodbye); +MODULE_DEPENDS(serial); + diff --git a/modules/zero.c b/modules/zero.c new file mode 100644 index 00000000..1a7f4a77 --- /dev/null +++ b/modules/zero.c @@ -0,0 +1,105 @@ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2014 Kevin Lange + * + * Null Device + * + */ + +#include +#include +#include + +static uint32_t read_null(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static uint32_t write_null(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static void open_null(fs_node_t *node, unsigned int flags); +static void close_null(fs_node_t *node); +static uint32_t read_zero(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static uint32_t write_zero(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static void open_zero(fs_node_t *node, unsigned int flags); +static void close_zero(fs_node_t *node); + +static uint32_t read_null(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + return 0; +} + +static uint32_t write_null(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + return 0; +} + +static void open_null(fs_node_t * node, unsigned int flags) { + return; +} + +static void close_null(fs_node_t * node) { + return; +} + +static uint32_t read_zero(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + memset(buffer, 0x00, size); + return 1; +} + +static uint32_t write_zero(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + return 0; +} + +static void open_zero(fs_node_t * node, unsigned int flags) { + return; +} + +static void close_zero(fs_node_t * node) { + return; +} + +static fs_node_t * null_device_create(void) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, "null"); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0666; + fnode->flags = FS_CHARDEVICE; + fnode->read = read_null; + fnode->write = write_null; + fnode->open = open_null; + fnode->close = close_null; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; + return fnode; +} + +static fs_node_t * zero_device_create(void) { + fs_node_t * fnode = malloc(sizeof(fs_node_t)); + memset(fnode, 0x00, sizeof(fs_node_t)); + fnode->inode = 0; + strcpy(fnode->name, "zero"); + fnode->uid = 0; + fnode->gid = 0; + fnode->mask = 0666; + fnode->flags = FS_CHARDEVICE; + fnode->read = read_zero; + fnode->write = write_zero; + fnode->open = open_zero; + fnode->close = close_zero; + fnode->readdir = NULL; + fnode->finddir = NULL; + fnode->ioctl = NULL; + return fnode; +} + +static int zero_initialize(void) { + vfs_mount("/dev/null", null_device_create()); + vfs_mount("/dev/zero", zero_device_create()); + return 0; +} + +static int zero_finalize(void) { + return 0; +} + + +MODULE_DEF(zero, zero_initialize, zero_finalize); diff --git a/util/generate_symbols.py b/util/generate_symbols.py new file mode 100755 index 00000000..d5907233 --- /dev/null +++ b/util/generate_symbols.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +""" + Generate a symbol table from nm output. +""" + +import sys + +# Write extern + type +def extern(name): + print(".extern %s" % (name)) + print(".type %s, @function" % (name)) + print("") + +# Write an entry +def entry(name): + print(".long %s" % (name)) + print(".asciz \"%s\"" % (name)) + print("") + +ignore = [ "abs", "kernel_symbols_start", "kernel_symbols_end" ] +lines = [ x.strip().split(" ")[2] for x in sys.stdin.readlines() if x not in ignore ] + +# Generate the assembly +print(".section .symbols") +print("") +for name in lines: + extern(name) + +print(".global kernel_symbols_start") +print("kernel_symbols_start:") +print("") +for name in lines: + entry(name) + +print(".global kernel_symbols_end") +print("kernel_symbols_end:") + + + diff --git a/util/make-version b/util/make-version new file mode 100755 index 00000000..be956665 --- /dev/null +++ b/util/make-version @@ -0,0 +1,10 @@ +#!/bin/bash + +VERSION=`git rev-parse --short HEAD` + +X=$(git status -s | grep -q '^.M') +if [ $? -eq 0 ]; then + VERSION="$VERSION-dirty" +fi + +echo -n $VERSION