PROJECT_ROOT := ..
VPATH := $(PROJECT_ROOT)/src
-ifeq ($(DEBUG_SERIAL),1)
-JRL_DEBUG := -DDEBUG_SERIAL
-endif
+ifeq ($(SERIAL_DEBUG), 1)
+JRLDEBUG= -DDEBUG_SERIAL
+else
+JRLDEBUG=
+endif
+
# Figure out if we're compiling with cygwin, http://cygwin.com
SYSTEM_NAME := $(shell uname -s)
gdt.c tss.c segment.c \
bget.c malloc.c \
synch.c kthread.c \
+ vm_cons.c debug.c \
+ pci.c \
serial.c reboot.c \
paging.c \
main.c
# ----------------------------------------------------------------------
# Flags used for all C source files
-GENERAL_OPTS := -O -Wall $(EXTRA_C_OPTS) $(JRL_DEBUG)
+
+GENERAL_OPTS := -O -Wall $(EXTRA_C_OPTS) $(JRLDEBUG)
CC_GENERAL_OPTS := $(GENERAL_OPTS) -Werror
# Flags used for kernel C source files
$(PAD) guest.img 1474560
guest-iso: guest-img
-
mkisofs -pad -b guest.img -R -o guest.iso guest.img
+geekos/idt.o: ../src/geekos/idt.c ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/defs.h ../include/geekos/idt.h \
+ ../include/geekos/int.h ../include/geekos/debug.h \
+ ../include/geekos/string.h ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h
+geekos/int.o: ../src/geekos/int.c ../include/geekos/idt.h \
+ ../include/geekos/int.h ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/defs.h ../include/geekos/irq.h \
+ ../include/geekos/debug.h ../include/geekos/string.h \
+ ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/cpu.h
+geekos/trap.o: ../src/geekos/trap.c ../include/geekos/idt.h \
+ ../include/geekos/int.h ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/defs.h ../include/geekos/kthread.h \
+ ../include/geekos/list.h ../include/geekos/trap.h \
+ ../include/geekos/debug.h ../include/geekos/string.h \
+ ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h
+geekos/irq.o: ../src/geekos/irq.c ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/idt.h ../include/geekos/int.h \
+ ../include/geekos/defs.h ../include/geekos/io.h ../include/geekos/irq.h
+geekos/io.o: ../src/geekos/io.c ../include/geekos/io.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h
+geekos/blockdev.o: ../src/geekos/blockdev.c ../include/geekos/errno.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/string.h ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/malloc.h ../include/geekos/int.h \
+ ../include/geekos/kassert.h ../include/geekos/defs.h \
+ ../include/geekos/kthread.h ../include/geekos/list.h \
+ ../include/geekos/synch.h ../include/geekos/blockdev.h \
+ ../include/geekos/fileio.h
+geekos/ide.o: ../src/geekos/ide.c ../include/geekos/serial.h \
+ ../include/geekos/irq.h ../include/geekos/int.h \
+ ../include/geekos/kassert.h ../include/geekos/screen.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/defs.h ../include/geekos/string.h \
+ ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/io.h ../include/geekos/errno.h \
+ ../include/geekos/malloc.h ../include/geekos/timer.h \
+ ../include/geekos/kthread.h ../include/geekos/list.h \
+ ../include/geekos/blockdev.h ../include/geekos/fileio.h \
+ ../include/geekos/ide.h
+geekos/keyboard.o: ../src/geekos/keyboard.c ../include/geekos/kthread.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/list.h ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/fmtout.h \
+ ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/irq.h ../include/geekos/int.h \
+ ../include/geekos/defs.h ../include/geekos/io.h \
+ ../include/geekos/keyboard.h
+geekos/screen.o: ../src/geekos/screen.c \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/kassert.h ../include/geekos/screen.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ ../include/geekos/io.h ../include/geekos/int.h ../include/geekos/defs.h
+geekos/timer.o: ../src/geekos/timer.c \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/limits.h \
+ ../include/geekos/io.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/int.h ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/fmtout.h \
+ ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/defs.h ../include/geekos/irq.h \
+ ../include/geekos/kthread.h ../include/geekos/list.h \
+ ../include/geekos/timer.h ../include/geekos/debug.h \
+ ../include/geekos/string.h ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h
+geekos/mem.o: ../src/geekos/mem.c ../include/geekos/defs.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/kassert.h ../include/geekos/screen.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/bootinfo.h ../include/geekos/gdt.h \
+ ../include/geekos/int.h ../include/geekos/malloc.h \
+ ../include/geekos/string.h ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/paging.h ../include/geekos/list.h \
+ ../include/geekos/mem.h
+geekos/crc32.o: ../src/geekos/crc32.c ../include/geekos/crc32.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/kassert.h ../include/geekos/screen.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/serial.h ../include/geekos/irq.h \
+ ../include/geekos/int.h ../include/geekos/defs.h \
+ ../include/geekos/string.h ../include/geekos/../libc/string.h \
+ ../include/geekos/io.h
+geekos/gdt.o: ../src/geekos/gdt.c ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/segment.h ../include/geekos/int.h \
+ ../include/geekos/defs.h ../include/geekos/tss.h \
+ ../include/geekos/gdt.h ../include/libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h
+geekos/tss.o: ../src/geekos/tss.c ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/defs.h ../include/geekos/gdt.h \
+ ../include/geekos/segment.h ../include/geekos/string.h \
+ ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/tss.h ../include/geekos/serial.h \
+ ../include/geekos/irq.h ../include/geekos/int.h ../include/geekos/io.h
+geekos/segment.o: ../src/geekos/segment.c ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/string.h ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/tss.h ../include/geekos/segment.h
+geekos/bget.o: ../src/geekos/bget.c ../include/geekos/string.h \
+ ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/kassert.h ../include/geekos/screen.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/bget.h
+geekos/malloc.o: ../src/geekos/malloc.c ../include/geekos/screen.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/int.h ../include/geekos/kassert.h \
+ ../include/geekos/defs.h ../include/geekos/bget.h \
+ ../include/geekos/malloc.h
+geekos/synch.o: ../src/geekos/synch.c ../include/geekos/kthread.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/list.h ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/fmtout.h \
+ ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/int.h ../include/geekos/defs.h \
+ ../include/geekos/synch.h
+geekos/kthread.o: ../src/geekos/kthread.c ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/defs.h ../include/geekos/int.h \
+ ../include/geekos/mem.h ../include/geekos/list.h \
+ ../include/geekos/paging.h ../include/geekos/bootinfo.h \
+ ../include/geekos/symbol.h ../include/geekos/string.h \
+ ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/kthread.h ../include/geekos/malloc.h \
+ ../include/geekos/serial.h ../include/geekos/irq.h \
+ ../include/geekos/io.h
+geekos/vm_cons.o: ../src/geekos/vm_cons.c ../include/geekos/fmtout.h \
+ ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/string.h ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/idt.h ../include/geekos/int.h \
+ ../include/geekos/kassert.h ../include/geekos/screen.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/defs.h ../include/geekos/vm_cons.h \
+ ../include/geekos/io.h
+geekos/debug.o: ../src/geekos/debug.c ../include/geekos/string.h \
+ ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/debug.h ../include/geekos/fmtout.h \
+ ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/vm_cons.h ../include/geekos/io.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/screen.h
+geekos/serial.o: ../src/geekos/serial.c ../include/geekos/serial.h \
+ ../include/geekos/irq.h ../include/geekos/int.h \
+ ../include/geekos/kassert.h ../include/geekos/screen.h \
+ ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/defs.h ../include/geekos/string.h \
+ ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/io.h ../include/geekos/reboot.h \
+ ../include/geekos/gdt.h ../include/geekos/idt.h
+geekos/reboot.o: ../src/geekos/reboot.c ../include/geekos/reboot.h \
+ ../include/libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h
+geekos/paging.o: ../src/geekos/paging.c ../include/geekos/string.h \
+ ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/int.h ../include/geekos/kassert.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/defs.h ../include/geekos/idt.h \
+ ../include/geekos/kthread.h ../include/geekos/list.h \
+ ../include/geekos/mem.h ../include/geekos/paging.h \
+ ../include/geekos/bootinfo.h ../include/geekos/malloc.h \
+ ../include/geekos/gdt.h ../include/geekos/segment.h \
+ ../include/geekos/crc32.h ../include/geekos/debug.h
+geekos/main.o: ../src/geekos/main.c ../include/geekos/bootinfo.h \
+ ../include/geekos/string.h ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/screen.h ../include/geekos/ktypes.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdbool.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/geekos/mem.h ../include/geekos/defs.h \
+ ../include/geekos/list.h ../include/geekos/kassert.h \
+ ../include/geekos/paging.h ../include/geekos/crc32.h \
+ ../include/geekos/tss.h ../include/geekos/int.h \
+ ../include/geekos/kthread.h ../include/geekos/trap.h \
+ ../include/geekos/timer.h ../include/geekos/keyboard.h \
+ ../include/geekos/io.h ../include/geekos/serial.h \
+ ../include/geekos/irq.h ../include/geekos/reboot.h \
+ ../include/geekos/ide.h ../include/geekos/vm_cons.h \
+ ../include/geekos/debug.h ../include/geekos/gdt.h
+common/fmtout.o: ../src/common/fmtout.c \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h \
+ ../include/geekos/string.h ../include/geekos/../libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/limits.h \
+ ../include/geekos/fmtout.h ../include/geekos/../libc/fmtout.h
+common/string.o: ../src/common/string.c ../include/libc/fmtout.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stdarg.h \
+ ../include/libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h
+common/memmove.o: ../src/common/memmove.c ../include/libc/string.h \
+ /home/jarusl/palacios/devtools/i386/lib/gcc/i386-elf/3.4.6/include/stddef.h
/*
* x86 port IO routines
* Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
- * $Revision: 1.1 $
+ * $Revision: 1.2 $
*
* This is free software. You are permitted to use,
* redistribute, and modify it as specified in the file "COPYING".
void Out_Word(ushort_t port, ushort_t value);
ushort_t In_Word(ushort_t port);
+void Out_DWord(ushort_t port, uint_t value);
+uint_t In_DWord(ushort_t port);
+
void IO_Delay(void);
#endif /* GEEKOS_IO_H */
return faultAddress;
}
-void SerialPrintPD(pde_t *pde);
-void SerialPrintPT(void *starting_address, pte_t *pte);
-void SerialPrintPDE(void *virtual_address, pde_t *pde);
-void SerialPrintPTE(void *virtual_address,pte_t *pte);
-void SerialDumpPageTables(pde_t *pde);
+void PrintPD(pde_t *pde);
+void PrintPT(void *starting_address, pte_t *pte);
+void PrintPDE(void *virtual_address, pde_t *pde);
+void PrintPTE(void *virtual_address,pte_t *pte);
+void DumpPageTables(pde_t *pde);
pte_t *LookupPage(void *vaddr);
#define GEEKOS_SCREEN_H
#include <geekos/ktypes.h>
+#include <geekos/fmtout.h>
#define BLACK 0
#define BLUE 1
void Put_String(const char* s);
void Put_Buf(const char* buf, ulong_t length);
void Print(const char* fmt, ...) __attribute__ ((format (printf, 1, 2)));
-
+void PrintList(const char * fmt, va_list ap);
#endif /* GEEKOS */
#endif /* GEEKOS_SCREEN_H */
#define DEFAULT_SERIAL_ADDR 0x3F8
-#ifndef SERIAL_PRINT
-#define SERIAL_PRINT 1
-#endif
-#ifndef SERIAL_PRINT_DEBUG
-#define SERIAL_PRINT_DEBUG 1
-#endif
-#ifndef SERIAL_PRINT_DEBUG_LEVEL
-#define SERIAL_PRINT_DEBUG_LEVEL 10
-#endif
-
-#define SERIAL_PRINT_MAXBUF 256
-
-
-#if SERIAL_PRINT
-#define SerialPrint(format, args...) \
-do { \
- char buf[SERIAL_PRINT_MAXBUF]; \
- snprintf( buf, SERIAL_PRINT_MAXBUF, format, ## args ) ; \
- SerialPutLineN(buf, SERIAL_PRINT_MAXBUF); \
-} while (0)
-#else
-#define SerialPrint(format, args...) do {} while (0)
-#endif
-
-
-#define PrintBoth(format, args...) \
-do { \
- Print(format, ## args); \
- SerialPrint(format, ##args); \
- } while (0)
-
-
-#if SERIAL_PRINT_DEBUG
-#define SerialPrintLevel(level, format, args...) \
-do { \
- char buf[SERIAL_PRINT_MAXBUF]; \
- if (level >= SERIAL_PRINT_DEBUG_LEVEL ) { \
- snprintf( buf, SERIAL_PRINT_MAXBUF, format, ## args ) ; \
- SerialPutLineN(buf, SERIAL_PRINT_MAXBUF); \
- } \
-} while (0)
-#else
-#define SerialPrintLevel(level, format, args...) do {} while (0)
-#endif
+void SerialPrint(const char * format, ...);
+void SerialPrintList(const char * format, va_list ap);
void SerialPutLine(char * line);
void SerialPutLineN(char * line, int len);
#include <geekos/crc32.h>
#include <geekos/kassert.h>
-#include <geekos/serial.h>
+#include <geekos/debug.h>
#define POLYNOMIAL (ulong_t)0xedb88320
static ulong_t crc_table[256];
#include <geekos/kassert.h>
#include <geekos/defs.h>
#include <geekos/idt.h>
-#include <geekos/serial.h>
+#include <geekos/debug.h>
/* ----------------------------------------------------------------------
* Private data and functions
-void DumpIDT()
-{
- int i;
- Print("IDT Contents:\n");
- for (i=0;i<NUM_IDT_ENTRIES/16;i++) {
- if (s_IDT[i].ig.present) {
- Print("%d: segmentselector=%u, offset=%u, offsetLow=%u, segmentSelector=%u, reserved=%u, signature=%u, dpl=%u, present=%u, offsetHigh=%u\n",
- i,
- s_IDT[i].ig.segmentSelector,
- (s_IDT[i].ig.offsetHigh<<16) + s_IDT[i].ig.offsetLow,
- s_IDT[i].ig.offsetLow,
- s_IDT[i].ig.segmentSelector,
- s_IDT[i].ig.reserved,
- s_IDT[i].ig.signature,
- s_IDT[i].ig.dpl,
- s_IDT[i].ig.present,
- s_IDT[i].ig.offsetHigh);
- }
- }
-}
-void SerialDumpIDT()
+void DumpIDT()
{
int i;
- SerialPrint("IDT Contents:\n");
+ PrintBoth("IDT Contents:\n");
for (i=0;i<NUM_IDT_ENTRIES;i++) {
if (s_IDT[i].ig.present) {
- SerialPrint("%d: segmentselector=%u, offset=%u, offsetLow=%u, segmentSelector=%u, reserved=%u, signature=%u, dpl=%u, present=%u, offsetHigh=%u\n",
+ PrintBoth("%d: segmentselector=%u, offset=%u, offsetLow=%u, segmentSelector=%u, reserved=%u, signature=%u, dpl=%u, present=%u, offsetHigh=%u\n",
i,
s_IDT[i].ig.segmentSelector,
(s_IDT[i].ig.offsetHigh<<16) + s_IDT[i].ig.offsetLow,
s_IDT[i].ig.dpl,
s_IDT[i].ig.present,
s_IDT[i].ig.offsetHigh);
- SerialPrint("\n");
+ PrintBoth("\n");
}
}
}
#include <geekos/screen.h>
#include <geekos/kassert.h>
#include <geekos/int.h>
-#include <geekos/serial.h>
+#include <geekos/irq.h>
+#include <geekos/debug.h>
#include <geekos/cpu.h>
{
Begin_IRQ(state);
- Print("Unexpected Interrupt! Ignoring!\n");
- SerialPrint("*** Unexpected interrupt! *** Ignoring!\n");
+ PrintBoth("*** Unexpected interrupt! *** Ignoring!\n");
Dump_Interrupt_State(state);
End_IRQ(state);
// STOP();
}
-#if 0
+
static void Print_Selector(const char* regName, uint_t value)
{
- Print("%s: index=%d, ti=%d, rpl=%d\n",
+ PrintBoth("%s: index=%d, ti=%d, rpl=%d\n",
regName, value >> 3, (value >> 2) & 1, value & 3);
}
-#endif
-static void SerialPrint_Selector(const char* regName, uint_t value)
-{
- SerialPrint("%s: index=%d, ti=%d, rpl=%d\n",
- regName, value >> 3, (value >> 2) & 1, value & 3);
-}
+
/* ----------------------------------------------------------------------
* Public functions
{
uint_t errorCode = state->errorCode;
- SerialPrint("eax=%08x ebx=%08x ecx=%08x edx=%08x\n"
+ PrintBoth("eax=%08x ebx=%08x ecx=%08x edx=%08x\n"
"esi=%08x edi=%08x ebp=%08x\n"
"eip=%08x cs=%08x eflags=%08x\n"
"Interrupt number=%d, error code=%d\n"
);
if (Is_User_Interrupt(state)) {
struct User_Interrupt_State *ustate = (struct User_Interrupt_State*) state;
- SerialPrint("user esp=%08x, user ss=%08x\n", ustate->espUser, ustate->ssUser);
+ PrintBoth("user esp=%08x, user ss=%08x\n", ustate->espUser, ustate->ssUser);
}
- SerialPrint_Selector("cs", state->cs);
- SerialPrint_Selector("ds", state->ds);
- SerialPrint_Selector("es", state->es);
- SerialPrint_Selector("fs", state->fs);
- SerialPrint_Selector("gs", state->gs);
+ Print_Selector("cs", state->cs);
+ Print_Selector("ds", state->ds);
+ Print_Selector("es", state->es);
+ Print_Selector("fs", state->fs);
+ Print_Selector("gs", state->gs);
}
);
}
-extern uchar_t InByteLL(ushort_t port);
-
/*
* Read a byte from an I/O port.
*/
uchar_t In_Byte(ushort_t port)
{
- /*
uchar_t value;
__asm__ __volatile__ (
);
return value;
- */
-
- return InByteLL(port);
}
/*
}
/*
- * Read a byte from an I/O port.
+ * Read a word from an I/O port.
*/
ushort_t In_Word(ushort_t port)
{
}
/*
+ * Write a double word to an I/O port.
+ */
+void Out_DWord(ushort_t port, uint_t value)
+{
+ __asm__ __volatile__ (
+ "outl %0, %1"
+ :
+ : "a" (value), "Nd" (port)
+ );
+}
+
+/*
+ * Read a double word from an I/O port.
+ */
+uint_t In_DWord(ushort_t port)
+{
+ uint_t value;
+
+ __asm__ __volatile__ (
+ "inl %1, %0"
+ : "=a" (value)
+ : "Nd" (port)
+ );
+
+ return value;
+}
+
+/*
* Short delay. May be needed when talking to some
* (slow) I/O devices.
*/
#include <geekos/string.h>
#include <geekos/kthread.h>
#include <geekos/malloc.h>
-#include <geekos/serial.h>
+#include <geekos/debug.h>
/* ----------------------------------------------------------------------
* Private data
* redistribute, and modify it as specified in the file "COPYING".
*/
+#include <geekos/debug.h>
#include <geekos/bootinfo.h>
#include <geekos/string.h>
#include <geekos/screen.h>
#include <geekos/mem.h>
#include <geekos/paging.h>
#include <geekos/ide.h>
-
+#include <geekos/vm_cons.h>
+#include <geekos/pci.h>
#include <geekos/gdt.h>
+
+#define TEST_PAGING 0
+#define TEST_PCI 1
+
/*
static inline unsigned int cpuid_ecx(unsigned int op)
{
while ((key_press = Wait_For_Key())) {
if (key_press == KEY_F4) {
- Print("\nToggling Speaker Port\n");
- SerialPrintLevel(100,"\nToggling Speaker Port\n");
+ PrintBoth("\nToggling Speaker Port\n");
*doIBuzz = (*doIBuzz + 1) % 2;
} else if (key_press == KEY_F5) {
- Print("\nMachine Restart\n");
- SerialPrintLevel(100,"\nMachine Restart\n");
+ PrintBoth("\nMachine Restart\n");
machine_real_restart();
}
}
Init_BSS();
Init_Screen();
InitSerial();
+
+ Init_VMCons();
Init_Mem(bootInfo);
Init_CRC32();
Init_TSS();
- SerialPrint("\n\nHello, Welcome to this horrid output-only serial interface\n");
- SerialPrint("Eventually, this will let us control the VMM\n\n");
+ PrintBoth("\n\nHello, Welcome to this horrid output-only serial interface\n");
+ PrintBoth("Eventually, this will let us control the VMM\n\n");
- SerialPrint("\n\n===>");
+ PrintBoth("\n\n===>");
- SerialPrintLevel(1000,"Launching Noisemaker and keyboard listener threads\n");
+ PrintBoth("Launching Noisemaker and keyboard listener threads\n");
key_thread = Start_Kernel_Thread(Keyboard_Listener, (ulong_t)&doIBuzz, PRIORITY_NORMAL, false);
spkr_thread = Start_Kernel_Thread(Buzzer, (ulong_t)&doIBuzz, PRIORITY_NORMAL, false);
- SerialPrintLevel(1000,"Next: setup GDT\n");
+ PrintBoth("Next: setup GDT\n");
- {
- int i = 0;
- for (i = 0; i < 1024; i++) {
- uint_t * addr = (uint_t *)0xa00000;
- uint_t foo = *addr;
- SerialPrint("Read From 0x%x=%d\n", (uint_t)addr, foo);
- }
+ if (TEST_PAGING) {
+ int i = 0;
+ for (i = 0; i < 1024; i++) {
+ uint_t * addr = (uint_t *)0xa00000;
+ uint_t foo = *addr;
+
+ PrintBoth("Read From 0x%x=%d\n", (uint_t)addr, foo);
+ }
+
+ // Invalidate_PG((void *)0x2000);
+
+ // VM_Test(bootInfo, 32);
+ //VM_Test(bootInfo, 1536);
}
- // Invalidate_PG((void *)0x2000);
- // VM_Test(bootInfo, 32);
- //VM_Test(bootInfo, 1536);
+
+ if (TEST_PCI) {
+ Init_PCI();
+
+
+ }
while(1);
//#include <geekos/vfs.h>
#include <geekos/crc32.h>
#include <geekos/paging.h>
-#include <geekos/serial.h>
+#include <geekos/debug.h>
/* ----------------------------------------------------------------------
* flag to indicate if debugging paging code
*/
int debugFaults = 0;
-#define Debug(args...) if (debugFaults) Print(args)
+#define Debug(args...) if (debugFaults) PrintBoth(args)
-void SerialPrintPD(pde_t *pde)
+void PrintPD(pde_t *pde)
{
uint_t i;
- SerialPrint("Page Directory at %p:\n",pde);
+ PrintBoth("Page Directory at %p:\n",pde);
for (i = 0; i < NUM_PAGE_DIR_ENTRIES; i++) {
if (pde[i].present) {
if ((i * PAGE_SIZE * 1024) > 0x40000000) {
- SerialPrintPDE((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),&(pde[i]));
+ PrintPDE((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),&(pde[i]));
}
}
}
}
-void SerialPrintPT(void *starting_address, pte_t *pte)
+void PrintPT(void *starting_address, pte_t *pte)
{
int i;
- SerialPrint("Page Table at %p:\n",pte);
+ PrintBoth("Page Table at %p:\n",pte);
for (i=0;i<NUM_PAGE_TABLE_ENTRIES;i++) {
if (pte[i].present) {
- SerialPrintPTE(starting_address + PAGE_SIZE*i,&(pte[i]));
+ PrintPTE(starting_address + PAGE_SIZE*i,&(pte[i]));
}
}
}
-void SerialPrintPDE(void *virtual_address, pde_t *pde)
+void PrintPDE(void *virtual_address, pde_t *pde)
{
- SerialPrint("PDE %p -> %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
+ Print("PDE %p -> %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
virtual_address,
(void*) (pde->pageTableBaseAddr << PAGE_POWER),
pde->present,
pde->kernelInfo);
}
-void SerialPrintPTE(void *virtual_address, pte_t *pte)
+void PrintPTE(void *virtual_address, pte_t *pte)
{
- SerialPrint("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, kernelInfo=%x\n",
+ PrintBoth("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, kernelInfo=%x\n",
virtual_address,
(void*)(pte->pageBaseAddr << PAGE_POWER),
pte->present,
}
-void SerialDumpPageTables(pde_t *pde)
+void DumpPageTables(pde_t *pde)
{
uint_t i;
- SerialPrint("Dumping the pages starting with the pde page at %p\n",pde);
+ PrintBoth("Dumping the pages starting with the pde page at %p\n",pde);
for (i = 0; i < NUM_PAGE_DIR_ENTRIES; i++) {
if (pde[i].present) {
if ((i * PAGE_SIZE * 1024) >= 0x40000000) {
- SerialPrintPDE((void *)(PAGE_SIZE * NUM_PAGE_TABLE_ENTRIES * i), &(pde[i]));
- SerialPrintPT((void *)(PAGE_SIZE * NUM_PAGE_TABLE_ENTRIES * i), (void *)(pde[i].pageTableBaseAddr << PAGE_POWER));
+ PrintPDE((void *)(PAGE_SIZE * NUM_PAGE_TABLE_ENTRIES * i), &(pde[i]));
+ PrintPT((void *)(PAGE_SIZE * NUM_PAGE_TABLE_ENTRIES * i), (void *)(pde[i].pageTableBaseAddr << PAGE_POWER));
}
}
}
g_freePageCount+=0;
- SerialPrintLevel(100,"Pid %d, Page Fault received, at address %x (%d pages free)\n",
+ PrintBoth("Pid %d, Page Fault received, at address %x (%d pages free)\n",
g_currentThread->pid, address, g_freePageCount);
if (faultCode.protectionViolation)
- SerialPrintLevel(100," Protection Violation, ");
+ PrintBoth(" Protection Violation, ");
else
- SerialPrintLevel(100," Non-present page, ");
+ PrintBoth(" Non-present page, ");
if (faultCode.writeFault)
- SerialPrintLevel(100,"Write Fault, ");
+ PrintBoth("Write Fault, ");
else
- SerialPrintLevel(100,"Read Fault, ");
+ PrintBoth("Read Fault, ");
if (faultCode.userModeFault)
- SerialPrintLevel(100,"in User Mode\n");
+ PrintBoth("in User Mode\n");
else
- SerialPrintLevel(100,"in Supervisor Mode\n");
+ PrintBoth("in Supervisor Mode\n");
}
/*
/* Get the address that caused the page fault */
address = Get_Page_Fault_Address();
- Debug("Page fault @%lx\n", address);
+ PrintBoth("Page fault @%lx\n", address);
/* Get the fault code */
faultCode = *((faultcode_t *) &(state->errorCode));
/* rest of your handling code here */
- SerialPrintLevel(100,"Unexpected Page Fault received\n");
+ PrintBoth("Unexpected Page Fault received\n");
Print_Fault_Info(address, faultCode);
Dump_Interrupt_State(state);
/* user faults just kill the process */
PrintBoth("Intitialing Virtual Memory\n");
if (checkPaging()) {
- SerialPrintLevel(100,"Paging is currently ON\n");
+ PrintBoth("Paging is currently ON\n");
return ;
}
- SerialPrintLevel(100,"Paging is currently OFF - initializing the pages for a 1-1 map\n");
+ PrintBoth("Paging is currently OFF - initializing the pages for a 1-1 map\n");
numpages=bootInfo->memSizeKB / (PAGE_SIZE/1024);
numpagetables = numpages / NUM_PAGE_TABLE_ENTRIES + ((numpages % NUM_PAGE_TABLE_ENTRIES) != 0 );
- SerialPrintLevel(100,"We need %d pages, and thus %d page tables, and one page directory\n",numpages, numpagetables);
+ PrintBoth("We need %d pages, and thus %d page tables, and one page directory\n",numpages, numpagetables);
pd = (pde_t*)Alloc_Page();
if (!pd) {
- SerialPrintLevel(100,"We are giving up since we can't allocate a page directory!\n");
+ PrintBoth("We are giving up since we can't allocate a page directory!\n");
return;
} else {
- SerialPrintLevel(100,"Our PDE is at physical address %p\n",pd);
+ PrintBoth("Our PDE is at physical address %p\n",pd);
}
for (i=0;i<NUM_PAGE_DIR_ENTRIES;i++) {
} else {
pt = (pte_t*)Alloc_Page();
if (!pt) {
- SerialPrintLevel(100,"We are giving up since we can't allocate page table %d\n",i);
+ PrintBoth("We are giving up since we can't allocate page table %d\n",i);
} else {
- //SerialPrintLevel(100,"Page Table %d is at physical address %p\n",i,pt);
+ //PrintBoth("Page Table %d is at physical address %p\n",i,pt);
}
pd[i].present=1;
pd[i].flags= VM_READ | VM_WRITE | VM_EXEC | VM_USER;
}
- SerialPrintLevel(100,"Done creating 1<->1 initial page tables\n");
- SerialPrintLevel(100,"Now installing page fault handler\n");
+ PrintBoth("Done creating 1<->1 initial page tables\n");
+ PrintBoth("Now installing page fault handler\n");
// SerialDumpPageTables(pd);
Install_Interrupt_Handler(14,Page_Fault_Handler);
- SerialPrintLevel(100,"Now turning on the paging bit!\n");
+ PrintBoth("Now turning on the paging bit!\n");
Enable_Paging(pd);
- SerialPrintLevel(100,"We are still alive after paging turned on!\n");
- SerialPrintLevel(100,"checkPaging returns %d\n",checkPaging());
+ PrintBoth("We are still alive after paging turned on!\n");
+ PrintBoth("checkPaging returns %d\n",checkPaging());
}
PrintBoth("Loading CR3\n");
Set_PDBR(pd);
- SerialDumpPageTables(pd);
+ DumpPageTables(pd);
PrintBoth("Writing to Test Area\n");
uint_t * test_ptr = (uint_t *)two_gig;
for (i = 0; i < num_test_pages; i++) {
- SerialPrint("Writing %d to %p\n", i, test_ptr);
+ PrintBoth("Writing %d to %p\n", i, test_ptr);
*test_ptr = (uint_t)i;
test_ptr += PAGE_SIZE / 4;
}
Set_PDBR(pd);
PrintBoth("Page Mapping Reversed\n");
- SerialDumpPageTables(pd);
+ DumpPageTables(pd);
PrintBoth("Page Consistency Check\n");
* Print to console using printf()-style formatting.
* Calls into Format_Output in common library.
*/
+
+static __inline__ void PrintInternal(const char * format, va_list ap) {
+ Format_Output(&s_outputSink, format, ap);
+}
+
+
void Print(const char *fmt, ...)
{
va_list args;
bool iflag = Begin_Int_Atomic();
va_start(args, fmt);
- Format_Output(&s_outputSink, fmt, args);
+ PrintInternal(fmt, args);
va_end(args);
End_Int_Atomic(iflag);
}
+void PrintList(const char * fmt, va_list ap) {
+ bool iflag = Begin_Int_Atomic();
+ PrintInternal(fmt, ap);
+ End_Int_Atomic(iflag);
+}
End_IRQ(state);
}
-void InitSerial() {
- Print("Initialzing Serial\n");
- Install_IRQ(COM1_IRQ, Serial_Interrupt_Handler);
- Enable_IRQ(COM1_IRQ);
- InitSerialAddr(DEFAULT_SERIAL_ADDR);
-}
void InitSerialAddr(unsigned short io_addr) {
serial_io_addr = io_addr;
SerialPrint("\n");
}
}
+
+
+static struct Output_Sink serial_output_sink;
+static void Serial_Emit(struct Output_Sink * o, int ch) {
+ SerialPutChar((unsigned char)ch);
+}
+static void Serial_Finish(struct Output_Sink * o) { return; }
+
+
+static void __inline__ SerialPrintInternal(const char * format, va_list ap) {
+ Format_Output(&serial_output_sink, format, ap);
+}
+
+
+void SerialPrint(const char * format, ...) {
+ va_list args;
+ bool iflag = Begin_Int_Atomic();
+
+ va_start(args, format);
+ SerialPrintInternal(format, args);
+ va_end(args);
+
+ End_Int_Atomic(iflag);
+}
+
+void SerialPrintList(const char * format, va_list ap) {
+ bool iflag = Begin_Int_Atomic();
+ SerialPrintInternal(format, ap);
+ End_Int_Atomic(iflag);
+
+}
+
+
+
+void InitSerial() {
+ Print("Initialzing Serial\n");
+
+ serial_output_sink.Emit = &Serial_Emit;
+ serial_output_sink.Finish = &Serial_Finish;
+
+ Install_IRQ(COM1_IRQ, Serial_Interrupt_Handler);
+ Enable_IRQ(COM1_IRQ);
+ InitSerialAddr(DEFAULT_SERIAL_ADDR);
+}
#include <geekos/kthread.h>
#include <geekos/timer.h>
-#include <geekos/serial.h>
+#include <geekos/debug.h>
#define HZ 100
Begin_IRQ(state);
- SerialPrintLevel(10,"Host Timer Interrupt Handler Running\n");
+ PrintBoth("Host Timer Interrupt Handler Running\n");
/* Update global and per-thread number of ticks */
++g_numTicks;
#include <geekos/kthread.h>
#include <geekos/defs.h>
#include <geekos/trap.h>
-#include <geekos/serial.h>
+#include <geekos/debug.h>
/*
* TODO: need to add handlers for other exceptions (such as bounds
static void GPF_Handler(struct Interrupt_State* state)
{
/* Send the thread to the reaper... */
- SerialPrintLevel(1000,"Exception %d received, killing thread %p\n",state->intNum, g_currentThread);
+ PrintBoth("Exception %d received, killing thread %p\n",state->intNum, g_currentThread);
Dump_Interrupt_State(state);
Exit(-1);
#include <geekos/string.h>
#include <geekos/tss.h>
-#include <geekos/serial.h>
+#include <geekos/debug.h>
/*
* We use one TSS in GeekOS.
ifeq ($(DEBUG_ALL),1)
- DEBUG_SECTIONS:= $(DEBUG_SECTIONS) -DDEBUG_SHADOW_PAGING -DDEBUG_NESTED_PAGING -DDEBUG_CTRL_REGS -DDEBUG_INTERRUPTS -DDEBUG_KEYBOARD -DDEBUG_PIC -DDEBUG_PIT -DDEBUG_NVRAM -DDEBUG_EMULATOR -DDEBUG_XED -DDEBUG_HALT -DDEBUG_DEV_MGR -DDEBUG_IO -DDEBUG_GENERIC -DDEBUG_RAMDISK
+ DEBUG_SECTIONS:= $(DEBUG_SECTIONS) -DDEBUG_SHADOW_PAGING -DDEBUG_NESTED_PAGING -DDEBUG_CTRL_REGS -DDEBUG_INTERRUPTS -DDEBUG_KEYBOARD -DDEBUG_PIC -DDEBUG_PIT -DDEBUG_NVRAM -DDEBUG_EMULATOR -DDEBUG_XED -DDEBUG_HALT -DDEBUG_DEV_MGR
+# -DDEBUG_IO -DDEBUG_GENERIC -DDEBUG_IDE
endif
endif
endif
-ifeq ($(DEBUG_RAMDISK),1)
-DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DDEBUG_RAMDISK
+ifeq ($(DEBUG_IDE),1)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DDEBUG_IDE
else
-ifeq ($(DEBUG_RAMDISK),0)
-DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_RAMDISK
-endif
-endif
-
-ifeq ($(TRACE_RAMDISK),1)
-DEBUG_SECTIONS := $(DEBUG_SECTIONS) -DTRACE_RAMDISK
-else
-ifeq ($(TRACE_RAMDSK),0)
-DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UTRACE_RAMDISK
+ifeq ($(DEBUG_IDE),0)
+DEBUG_SECTIONS := $(DEBUG_SECTIONS) -UDEBUG_IDE
endif
endif
devices/8259a.o \
devices/8254.o \
devices/serial.o \
- devices/ramdisk.o \
- devices/cdrom.o \
devices/bochs_debug.o \
devices/os_debug.o \
devices/apic.o \
devices/io_apic.o \
devices/pci.o \
devices/para_net.o \
+ devices/ide.o \
+ devices/ram_cd.o \
+# devices/cdrom.o \
+# devices/ramdisk.o \
# devices/vnic.o \
$(DEVICES_OBJS) :: EXTRA_CFLAGS = \
/*
- * Copyright (C) 2002 MandrakeSoft S.A.
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
*
- * MandrakeSoft S.A.
- * 43, rue d'Aboukir
- * 75002 Paris - France
- * http://www.linux-mandrake.com/
- * http://www.mandrakesoft.com/
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Major modifications made for the V3VEE project
- *
* The V3VEE Project is a joint project between Northwestern University
* and the University of New Mexico. You can find out more at
* http://www.v3vee.org
- *
- * Copyright (c) 2008, Zheng Cui <cuizheng@cs.unm.edu>
- * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
* Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
- * All rights reserved for original changes
- *
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
*/
#ifndef __DEVICES_IDE_H__
#define __DEVICES_IDE_H__
#ifdef __V3VEE__
-
-
-#include <palacios/vmm_types.h>
#include <palacios/vm_dev.h>
-typedef long off_t;
-typedef sint32_t ssize_t;
-typedef unsigned int rd_bool;
-typedef uchar_t Bit8u;
-typedef ushort_t Bit16u;
-typedef uint32_t Bit32u;
-typedef uint64_t Bit64u;
-
-
-
-#define MAX_ATA_CHANNEL 4
-
-typedef enum _sense {
- SENSE_NONE = 0,
- SENSE_NOT_READY = 2,
- SENSE_ILLEGAL_REQUEST = 5,
- SENSE_UNIT_ATTENTION = 6
-} sense_t ;
-
-typedef enum _asc {
- ASC_INV_FIELD_IN_CMD_PACKET = 0x24,
- ASC_MEDIUM_NOT_PRESENT = 0x3a,
- ASC_SAVING_PARAMETERS_NOT_SUPPORTED = 0x39,
- ASC_LOGICAL_BLOCK_OOR = 0x21
-} asc_t ;
-
-
-
-typedef struct {
- unsigned cylinders;
- unsigned heads;
- unsigned sectors;
-} device_image_t;
-
-
-
-
-struct interrupt_reason_t {
- unsigned c_d : 1;
- unsigned i_o : 1;
- unsigned rel : 1;
- unsigned tag : 5;
-};
-
-
-struct controller_status {
- rd_bool busy;
- rd_bool drive_ready;
- rd_bool write_fault;
- rd_bool seek_complete;
- rd_bool drq;
- rd_bool corrected_data;
- rd_bool index_pulse;
- unsigned int index_pulse_count;
- rd_bool err;
-};
-
-
-
-
-
-struct sense_info_t {
- sense_t sense_key;
-
- struct {
- Bit8u arr[4];
- } information;
-
- struct {
- Bit8u arr[4];
- } specific_inf;
-
- struct {
- Bit8u arr[3];
- } key_spec;
-
- Bit8u fruc;
- Bit8u asc;
- Bit8u ascq;
-};
-
-struct error_recovery_t {
- unsigned char data[8];
-};
-
-struct cdrom_t {
- rd_bool ready;
- rd_bool locked;
-
- struct cdrom_ops * cd;
-
- uint32_t capacity;
- int next_lba;
- int remaining_blocks;
-
- struct currentStruct {
- struct error_recovery_t error_recovery;
- } current;
-
-};
-
-struct atapi_t {
- uint8_t command;
- int drq_bytes;
- int total_bytes_remaining;
-};
-
-
-typedef enum { IDE_NONE, IDE_DISK, IDE_CDROM } device_type_t;
-
-struct controller_t {
- struct controller_status status;
- Bit8u error_register;
- Bit8u head_no;
-
- union {
- Bit8u sector_count;
- struct interrupt_reason_t interrupt_reason;
- };
-
-
- Bit8u sector_no;
-
- union {
- Bit16u cylinder_no;
- Bit16u byte_count;
- };
-
- Bit8u buffer[2048];
- Bit32u buffer_index;
- Bit32u drq_index;
- Bit8u current_command;
- Bit8u sectors_per_block;
- Bit8u lba_mode;
-
- struct vm_device * pci;
+typedef enum {IDE_DISK, IDE_CDROM, IDE_NONE} v3_ide_dev_type_t;
- struct {
- rd_bool reset; // 0=normal, 1=reset controller
- rd_bool disable_irq; // 0=allow irq, 1=disable irq
- } control;
+struct v3_ide_cd_ops {
+ uint32_t (*get_capacity)(void * private_data);
+ // Reads always operate on 2048 byte blocks
+ int (*read)(uint8_t * buf, int lba, void * private_data);
- Bit8u reset_in_progress;
- Bit8u features;
};
+struct v3_ide_hd_ops {
+
-
-struct drive_t {
- device_image_t hard_drive;
- device_type_t device_type;
- // 512 byte buffer for ID drive command
- // These words are stored in native word endian format, as
- // they are fetched and returned via a return(), so
- // there's no need to keep them in x86 endian format.
- Bit16u id_drive[256];
-
- struct controller_t controller;
- struct cdrom_t cdrom;
- struct sense_info_t sense;
- struct atapi_t atapi;
-
- /* JRL */
- void * private_data;
-
- Bit8u model_no[41];
-};
-
-
-// FIXME:
-// For each ATA channel we should have one controller struct
-// and an array of two drive structs
-struct channel_t {
- struct drive_t drives[2];
- unsigned drive_select;
-
- Bit16u ioaddr1;
- Bit16u ioaddr2;
- Bit8u irq;
-};
-
-
-
-struct ramdisk_t {
- struct channel_t channels[MAX_ATA_CHANNEL];
};
+int v3_ide_register_cdrom(struct vm_device * ide,
+ uint_t bus_num,
+ uint_t drive_num,
+ char * drive_name,
+ struct v3_ide_cd_ops * ops,
+ void * private_data);
+int v3_ide_register_harddisk(struct vm_device * ide,
+ uint_t bus_num,
+ uint_t drive_num,
+ char * drive_name,
+ struct v3_ide_hd_ops * ops,
+ void * private_data);
+struct vm_device * v3_create_ide();
#endif
-#if 0
-
-// FLAT MODE
-// Open a image. Returns non-negative if successful.
-//int open (const char* pathname);
-
-// Open an image with specific flags. Returns non-negative if successful.
-int rd_open (const char* pathname, int flags);
-
-// Close the image.
-void rd_close ();
-
-// Position ourselves. Return the resulting offset from the
-// beginning of the file.
-off_t rd_lseek (off_t offset, int whence);
-
-// Read count bytes to the buffer buf. Return the number of
-// bytes read (count).
-ssize_t rd_read (void* buf, size_t count);
-
-// Write count bytes from buf. Return the number of bytes
-// written (count).
-ssize_t rd_write (const void* buf, size_t count);
-
-
-#endif
struct v3_pci_bar {
pci_bar_type_t type;
- int mem_hook;
- int num_pages;
- int (*bar_update)(struct pci_device * pci_dev, uint_t bar);
+
+ union {
+ struct {
+ int num_pages;
+ addr_t default_base_addr;
+ int (*mem_read)(addr_t guest_addr, void * dst, uint_t length, void * private_data);
+ int (*mem_write)(addr_t guest_addr, void * src, uint_t length, void * private_data);
+ };
+
+ struct {
+ int num_ports;
+ uint16_t default_base_port;
+ int (*io_read)(ushort_t port, void * dst, uint_t length, struct vm_device * dev);
+ int (*io_write)(ushort_t port, void * src, uint_t length, struct vm_device * dev);
+ };
+ };
// Internal PCI data
int updated;
for (j = 7; j >= 0; j--) {
uchar_t flag = 0x1 << j;
if ((*svc_major) & flag) {
-
-
return ((i * 8) + j);
}
}
for (j = 7; j >= 0; j--) {
uchar_t flag = 0x1 << j;
if ((*req_major) & flag) {
-
-
return ((i * 8) + j);
}
}
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#ifndef __DEVICES_ATAPI_TYPES_H__
+#define __DEVICES_ATAPI_TYPES_H__
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_types.h>
+
+typedef enum {
+ ATAPI_SEN_NONE = 0,
+ ATAPI_SEN_NOT_RDY = 2,
+ ATAPI_SEN_ILL_REQ = 5,
+ ATAPI_SEN_UNIT_ATTNT = 6
+} atapi_sense_key_t ;
+
+typedef enum {
+ ASC_INV_CMD_FIELD = 0x24,
+ ASC_MEDIA_NOT_PRESENT = 0x3a,
+ ASC_SAVE_PARAM_NOT_SUPPORTED = 0x39,
+ ASC_LOG_BLK_OOR = 0x21 /* LOGICAL BLOCK OUT OF RANGE */
+} atapi_add_sense_code_t ;
+
+struct atapi_irq_flags {
+ uint8_t c_d : 1;
+ uint8_t io_dir : 1;
+ uint8_t rel : 1;
+ uint8_t tag : 5;
+} __attribute__((packed));
+
+
+
+struct atapi_sense_data {
+ union {
+ uint8_t buf[18];
+ struct {
+ uint8_t header;
+ uint8_t rsvd1;
+ uint8_t sense_key; // atapi_sense_key_t
+ uint8_t info[4];
+ uint8_t read_len; // num bytes past this point
+ uint8_t spec_info[4];
+ uint8_t asc; // atapi_add_sense_code_t
+ uint8_t ascq; // ??
+ uint8_t fruc; // ??
+ uint8_t key_spec[3];
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
+struct atapi_read10_cmd {
+ uint8_t atapi_cmd;
+ uint8_t rel_addr : 1;
+ uint8_t rsvd1 : 2;
+ uint8_t force_access : 1; // can't use cache for data
+ uint8_t disable_pg_out : 1;
+ uint8_t lun : 3;
+ uint32_t lba;
+ uint8_t rsvd2;
+ uint16_t xfer_len;
+ uint8_t ctrl;
+} __attribute__((packed));
+
+
+struct atapi_mode_sense_cmd {
+ uint8_t atapi_cmd; // 0x5a
+ uint8_t rsvd1 : 3;
+ uint8_t disable_blk_desc : 1;
+ uint8_t long_lba_acc : 1;
+ uint8_t lun : 3;
+ uint8_t page_code : 6;
+ uint8_t page_ctrl : 2;
+ uint8_t sub_page_code;
+ uint8_t rsvd2[3];
+ uint16_t alloc_len;
+ uint8_t link : 1;
+ uint8_t flag : 1;
+ uint8_t naca : 1;
+ uint8_t rsvd3 : 3;
+ uint8_t vendor_specific : 2;
+} __attribute__((packed));
+
+struct atapi_mode_sense_hdr {
+ uint16_t mode_data_len;
+ uint8_t media_type_code;
+ uint8_t rsvd[2];
+ uint16_t blk_desc_len;
+} __attribute__((packed));
+
+
+struct atapi_rd_capacity_cmd {
+ uint8_t atapi_cmd; // 0x25
+ uint8_t obsolete : 1;
+ uint8_t rsvd1 : 4;
+ uint8_t lun : 3;
+ uint32_t lba;
+ uint16_t rsvd2;
+ uint8_t pmi;
+ uint8_t rsvd3 : 7;
+ uint8_t link : 1;
+ uint8_t flag : 1;
+ uint8_t naca : 1;
+ uint8_t rsvd4 : 3;
+ uint8_t vendor_spec : 2;
+} __attribute__((packed));
+
+
+struct atapi_rd_capacity_resp {
+ uint32_t lba;
+ uint32_t block_len;
+} __attribute__((packed));
+
+struct atapi_config_cmd {
+ uint8_t atapi_cmd; // 0x46
+ uint8_t rt : 2;
+ uint8_t rsvd1 : 3;
+ uint8_t lun : 3;
+ uint16_t start_feature_num;
+ uint8_t rsvd2[3];
+ uint16_t alloc_len;
+ uint8_t link : 1;
+ uint8_t flag : 1;
+ uint8_t naca : 1;
+ uint8_t rsvd3 : 3;
+ uint8_t vendor_specific : 2;
+} __attribute__((packed));
+
+struct atapi_config_resp {
+ uint32_t data_len;
+ uint16_t rsvd;
+ uint16_t cur_profile;
+} __attribute__((packed));
+
+
+struct atapi_rd_toc_cmd {
+ uint8_t atapi_cmd; // 0x43
+ uint8_t rsvd1 : 1;
+ uint8_t msf : 1;
+ uint8_t rsvd2 : 3;
+ uint8_t lun : 3;
+ uint8_t format : 4;
+ uint8_t rsvd3 : 4;
+ uint8_t rsvd4[3];
+ uint8_t track_num;
+ uint16_t alloc_len;
+ uint8_t link : 1;
+ uint8_t flag : 1;
+ uint8_t naca : 1;
+ uint8_t rsvd5 : 3;
+ uint8_t vendor_specific : 2;
+} __attribute__((packed));
+
+struct atapi_rd_toc_resp {
+ uint16_t data_len;
+ uint8_t first_track_num;
+ uint8_t last_track_num;
+
+ struct {
+ uint8_t rsvd;
+ uint8_t ctrl : 4;
+ uint8_t adr : 4;
+ uint8_t track_num;
+ uint8_t rsvd2;
+ uint32_t start_addr;
+ } track_descs[0] __attribute__((packed)) ;
+
+} __attribute__((packed));
+
+
+struct atapi_error_recovery {
+ uint8_t page_code : 6;
+ uint8_t rsvd : 1;
+ uint8_t page_ctrl : 1;
+ uint8_t page_len;
+ uint8_t dcr : 1;
+ uint8_t dte : 1;
+ uint8_t per : 1;
+ uint8_t rsvd1 : 1;
+ uint8_t rc : 1;
+ uint8_t tb : 1;
+ uint8_t arre : 1;
+ uint8_t awre : 1;
+ uint8_t rd_retry_cnt;
+ uint8_t correct_spin;
+ uint8_t head_offset;
+ uint8_t data_strobe_offset;
+ uint8_t emcdr : 2;
+ uint8_t rsvd2 : 6;
+ uint8_t wr_retry_cnt;
+ uint8_t rsvd3;
+ uint16_t recovery_time_limit;
+} __attribute__((packed));
+
+
+struct atapi_cdrom_caps {
+ uint8_t page_code : 6;
+ uint8_t rsvd : 1;
+ uint8_t page_ctrl : 1;
+ uint8_t page_len;
+ uint8_t cdr_rd : 1;
+ uint8_t cdrw_rd : 1;
+ uint8_t mthd_2 : 1;
+ uint8_t dvdrom_rd : 1;
+ uint8_t dvdr_rd : 1;
+ uint8_t dvdram_rd : 1;
+ uint8_t rsvd1 : 2;
+ uint8_t cdr_wr : 1;
+ uint8_t cdrw_wr : 1;
+ uint8_t tst_wr : 1;
+ uint8_t rsvd2 : 1;
+ uint8_t dvdr_wr : 1;
+ uint8_t dvdram_wr : 1;
+ uint8_t rsvd3 : 2;
+ uint8_t audio_play : 1;
+ uint8_t composite : 1;
+ uint8_t digi_port1 : 1;
+ uint8_t digi_port2 : 1;
+ uint8_t mode2_form1 : 1;
+ uint8_t mode2_form2 : 1;
+ uint8_t multisession : 1;
+ uint8_t BUF : 1;
+ uint8_t cd_da : 1;
+ uint8_t cdda_str_acc : 1;
+ uint8_t rw_supported : 1;
+ uint8_t rw_dc : 1;
+ uint8_t c2_ptrs_supp : 1;
+ uint8_t isrc : 1;
+ uint8_t upc : 1;
+ uint8_t rd_bar_cd_cap : 1;
+ uint8_t lock : 1;
+ uint8_t lock_state : 1;
+ uint8_t prevent_jmpr : 1;
+ uint8_t eject : 1;
+ uint8_t rsvd4 : 1;
+ uint8_t lmt : 3;
+ uint8_t sep_vol : 1;
+ uint8_t sep_chnl_mute : 1;
+ uint8_t sdp : 1;
+ uint8_t sss : 1;
+ uint8_t side_chg_cap : 1;
+ uint8_t rw_in_lead_rd : 1;
+ uint8_t rsvd5 : 2;
+ uint16_t obsolete1;
+ uint16_t num_vols_supp;
+ uint16_t lun_buf_size; // in KBytes
+ uint16_t obsolete2;
+ uint8_t obsolete3;
+ uint8_t rsvd6 : 1;
+ uint8_t bckf : 1;
+ uint8_t rck : 1;
+ uint8_t lsbf : 1;
+ uint8_t len : 2;
+ uint8_t rsvd7 : 2;
+ uint16_t obsolete4[2];
+ uint16_t cp_mgmnt_rev_supp;
+ uint8_t rsvd8;
+ uint8_t rot_ctrl_sel : 2;
+ uint8_t rsvd9 : 6;
+ uint16_t cur_wr_spd; // KBytes/sec
+ uint16_t num_lun_wr_spd_dsc_tbls;
+ // lun write speed descriptor tables
+} __attribute__((packed));
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#define ATAPI_PACKET_SIZE 12
+#define ATAPI_BLOCK_SIZE 2048
+
+#include "atapi-types.h"
+
+
+/* ATAPI sucks...
+ * The OS will write to the cylinder register the number of bytes it wants to read
+ * however the device can change that value
+ *
+ */
+static int atapi_update_req_len(struct vm_device * dev, struct ide_channel * channel, uint_t xfer_len) {
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ // PrintDebug("Updating request length (pre=%d)\n", drive->req_len);
+
+ if (drive->req_len == 0) {
+ PrintError("ATAPI Error: request of length 0\n");
+ return -1;
+ }
+
+
+ channel->status.busy = 0;
+ channel->status.data_req = 1;
+ channel->status.error = 0;
+
+ drive->irq_flags.io_dir = 1;
+ drive->irq_flags.c_d = 0;
+
+ // make count even
+ if (drive->req_len % 2) {
+ drive->req_len -= 1;
+ }
+
+ // if the device can't return as much as the OS requested
+ if (drive->req_len > xfer_len) {
+ drive->req_len = xfer_len;
+ }
+
+ // PrintDebug("Updating request length (post=%d)\n", drive->req_len);
+
+ return 0;
+}
+
+
+
+// This is for simple commands that don't need to sanity check the req_len
+static void atapi_setup_cmd_resp(struct vm_device * dev, struct ide_channel * channel, uint_t xfer_len) {
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ drive->transfer_length = xfer_len;
+ drive->transfer_index = 0;
+ drive->req_len = drive->transfer_length;
+
+ drive->irq_flags.io_dir = 1;
+ drive->irq_flags.c_d = 0;
+
+ channel->status.busy = 0;
+ channel->status.data_req = 1;
+ channel->status.error = 0;
+
+ ide_raise_irq(dev, channel);
+}
+
+static void atapi_cmd_error(struct vm_device * dev, struct ide_channel * channel,
+ atapi_sense_key_t sense_key, atapi_add_sense_code_t asc) {
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ // overload error register with ATAPI value
+ channel->error_reg.val = sense_key << 4;
+
+ channel->status.busy = 0;
+ channel->status.ready = 1;
+ channel->status.write_fault = 0;
+ channel->status.data_req = 0;
+ channel->status.error = 1;
+
+ drive->cd_state.sense.header = 0xf0;
+ drive->cd_state.sense.rsvd1 = 0x00;
+ drive->cd_state.sense.read_len = 0x0a;
+ drive->cd_state.sense.sense_key = sense_key;
+ drive->cd_state.sense.asc = asc;
+
+
+ drive->irq_flags.io_dir = 1;
+ drive->irq_flags.c_d = 1;
+ drive->irq_flags.rel = 0;
+
+ ide_raise_irq(dev, channel);
+}
+
+
+static void atapi_cmd_nop(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ channel->status.busy = 0;
+ channel->status.ready = 1;
+ channel->status.data_req = 0;
+ channel->status.error = 0;
+
+ drive->irq_flags.io_dir = 1;
+ drive->irq_flags.c_d = 1;
+ drive->irq_flags.rel = 0;
+
+ ide_raise_irq(dev, channel);
+}
+
+
+
+static int atapi_read_chunk(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ int ret = drive->cd_ops->read(drive->data_buf, drive->cd_state.current_lba, drive->private_data);
+
+ if (ret == -1) {
+ PrintError("IDE: Error reading CD block (LBA=%x)\n", drive->cd_state.current_lba);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int atapi_update_data_buf(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ switch (drive->cd_state.atapi_cmd) {
+ case 0x28: // read(10)
+ case 0xa8: // read(12)
+
+ // Update lba address to point to next block
+ drive->cd_state.current_lba++;
+
+ // read the next block
+ return atapi_read_chunk(dev, channel);
+
+ default:
+ PrintError("Unhandled ATAPI command in update buffer %x\n", drive->cd_state.atapi_cmd);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+ struct atapi_read10_cmd * cmd = (struct atapi_read10_cmd *)(drive->data_buf);
+ uint32_t lba = be_to_le_32(cmd->lba);
+ uint16_t xfer_len = be_to_le_16(cmd->xfer_len);
+
+ /* Check if cd is ready
+ * if not: atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
+ */
+
+ if (xfer_len == 0) {
+ atapi_cmd_nop(dev, channel);
+ return 0;
+ }
+
+ if ((lba + xfer_len) > drive->cd_ops->get_capacity(drive->private_data)) {
+ atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_LOG_BLK_OOR);
+ ide_raise_irq(dev, channel);
+ return 0;}
+
+ // PrintDebug("Reading %d blocks from LBA 0x%x\n", xfer_len, lba);
+
+ drive->cd_state.current_lba = lba;
+
+ // Update the request length value in the cylinder registers
+
+ if (atapi_read_chunk(dev, channel) == -1) {
+ PrintError("IDE: Could not read initial chunk from CD\n");
+ return -1;
+ }
+
+ drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE;
+ drive->transfer_index = 0;
+
+ // Length of ATAPI buffer sits in cylinder registers
+ // This is weird... The host sets this value to say what it would like to transfer,
+ // if it is larger than the correct size, the device shrinks it to the correct size
+ if (atapi_update_req_len(dev, channel, ATAPI_BLOCK_SIZE) == -1) {
+ PrintError("Could not update initial request length\n");
+ return -1;
+ }
+
+ ide_raise_irq(dev, channel);
+
+ return 0;
+}
+
+
+
+static void atapi_req_sense(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ memcpy(drive->data_buf, drive->cd_state.sense.buf, sizeof(drive->cd_state.sense.buf));
+
+ atapi_setup_cmd_resp(dev, channel, 18);
+}
+
+
+
+static int atapi_get_capacity(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+ struct atapi_rd_capacity_resp * resp = (struct atapi_rd_capacity_resp *)(drive->data_buf);
+ uint32_t capacity = drive->cd_ops->get_capacity(drive->private_data);
+
+ resp->lba = le_to_be_32(capacity);
+ resp->block_len = le_to_be_32(ATAPI_BLOCK_SIZE);
+
+ atapi_setup_cmd_resp(dev, channel, sizeof(struct atapi_rd_capacity_resp));
+
+ return 0;
+}
+
+static int atapi_get_config(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+ struct atapi_config_cmd * cmd = (struct atapi_config_cmd *)(drive->data_buf);
+ uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
+ struct atapi_config_resp * resp = (struct atapi_config_resp *)(drive->data_buf);
+ int xfer_len = 8;
+
+ memset(resp, 0, sizeof(struct atapi_config_resp));
+
+ resp->data_len = le_to_be_32(xfer_len - 4);
+
+ if (alloc_len < xfer_len) {
+ xfer_len = alloc_len;
+ }
+
+ atapi_setup_cmd_resp(dev, channel, xfer_len);
+
+ return 0;
+}
+
+
+static int atapi_read_toc(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+ struct atapi_rd_toc_cmd * cmd = (struct atapi_rd_toc_cmd *)(drive->data_buf);
+ uint16_t alloc_len = be_to_le_16(cmd->alloc_len);
+ struct atapi_rd_toc_resp * resp = (struct atapi_rd_toc_resp *)(drive->data_buf);
+
+ int xfer_len = 12;
+
+ memset(resp, 0, sizeof(struct atapi_rd_toc_resp));
+
+ resp->data_len = le_to_be_16(10);
+ resp->first_track_num = 1;
+ resp->last_track_num = 1;
+
+ // we don't handle multi session
+ // we'll just treat it the same as single session
+ if ((cmd->format == 0) || (cmd->format == 1)) {
+ memset(&(resp->track_descs[0]), 0, 8);
+
+ if (alloc_len < xfer_len) {
+ xfer_len = alloc_len;
+ }
+
+ atapi_setup_cmd_resp(dev, channel, xfer_len);
+ } else {
+ PrintError("Unhandled Format (%d)\n", cmd->format);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int atapi_mode_sense_cur_values(struct vm_device * dev, struct ide_channel * channel,
+ struct atapi_mode_sense_cmd * sense_cmd) {
+ struct ide_drive * drive = get_selected_drive(channel);
+ struct atapi_mode_sense_hdr * hdr = (struct atapi_mode_sense_hdr *)(drive->data_buf);
+ uint_t resp_len = sizeof(struct atapi_mode_sense_hdr);
+ uint16_t alloc_len = be_to_le_16(sense_cmd->alloc_len);
+ PrintDebug("Page Code: %x\n", sense_cmd->page_code);
+ PrintDebug("Alloc len: %d\n", alloc_len);
+
+ switch (sense_cmd->page_code) {
+
+ case 0x01: { // error recovery
+ struct atapi_error_recovery * err = NULL;
+ err = (struct atapi_error_recovery *)(drive->data_buf +
+ sizeof(struct atapi_mode_sense_hdr));
+
+ memcpy(err, &(drive->cd_state.err_recovery), sizeof(struct atapi_error_recovery));
+
+ resp_len += sizeof(struct atapi_error_recovery);
+
+ hdr->mode_data_len = le_to_be_16(resp_len - 2);
+
+ break;
+ }
+ case 0x2a: { // CDROM caps and mech. status
+ struct atapi_cdrom_caps * caps = NULL;
+ caps = (struct atapi_cdrom_caps *)(drive->data_buf + sizeof(struct atapi_mode_sense_hdr));
+
+
+ memset(caps, 0, sizeof(struct atapi_cdrom_caps));
+
+ resp_len += sizeof(struct atapi_cdrom_caps);
+
+ hdr->mode_data_len = le_to_be_16(resp_len - 2);
+
+ caps->page_code = 0x2a;
+ caps->page_len = 0x12;
+ caps->mode2_form1 = 1;
+ caps->mode2_form2 = 1;
+ caps->multisession = 1;
+ caps->isrc = 1;
+ caps->upc = 1;
+
+ /* JRL TODO: These are dynamic caps */
+ caps->lock = 1;
+ caps->lock_state = 0;
+ caps->eject = 1;
+
+ caps->lmt = 1;
+ caps->obsolete1 = le_to_be_16(0x2c2);
+ caps->num_vols_supp = le_to_be_16(2);
+
+ caps->lun_buf_size = le_to_be_16(512);
+ caps->obsolete2 = le_to_be_16(0x2c2);
+
+ break;
+ }
+ case 0x0d:
+ case 0x0e:
+ case 0x3f:
+ default:
+ PrintError("ATAPI: Mode sense Page Code not supported (%x)\n", sense_cmd->page_code);
+ atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
+ ide_raise_irq(dev, channel);
+ return 0;
+ }
+
+
+ // We do this after error checking, because its only valid if everything worked
+ memset(hdr, 0, sizeof(struct atapi_mode_sense_hdr));
+ hdr->media_type_code = 0x70;
+
+ PrintDebug("resp_len=%d\n", resp_len);
+
+ drive->transfer_length = (resp_len > alloc_len) ? alloc_len : resp_len;
+ drive->transfer_index = 0;
+ atapi_update_req_len(dev, channel, drive->transfer_length);
+
+ ide_raise_irq(dev, channel);
+
+ return 0;
+}
+
+
+static int atapi_mode_sense(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+ struct atapi_mode_sense_cmd * sense_cmd = (struct atapi_mode_sense_cmd *)(drive->data_buf);
+
+ switch (sense_cmd->page_ctrl) {
+ case 0x00: // Current values
+ return atapi_mode_sense_cur_values(dev, channel, sense_cmd);
+ case 0x01: // Changeable values
+ case 0x02: // default values
+ case 0x03: // saved values
+ default:
+ PrintError("ATAPI: Mode sense mode not supported (%x)\n", sense_cmd->page_ctrl);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int atapi_handle_packet(struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+ uint8_t cmd = drive->data_buf[0];
+
+ PrintDebug("IDE: ATAPI Command %x\n", cmd);
+
+ drive->cd_state.atapi_cmd = cmd;
+
+ switch (cmd) {
+ case 0x00: // test unit ready
+ atapi_cmd_nop(dev, channel);
+
+ /* if drive not ready:
+ atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT)
+ */
+ break;
+ case 0x03: // request sense
+ atapi_req_sense(dev, channel);
+ break;
+
+ case 0x28: // read(10)
+ if (atapi_read10(dev, channel) == -1) {
+ PrintError("IDE: Error in ATAPI read (%x)\n", cmd);
+ return -1;
+ }
+ break;
+
+ case 0x5a: // mode sense
+ if (atapi_mode_sense(dev, channel) == -1) {
+ PrintError("IDE: Error in ATAPI mode sense (%x)\n", cmd);
+ return -1;
+ }
+ break;
+
+
+ case 0x25: // read cdrom capacity
+ if (atapi_get_capacity(dev, channel) == -1) {
+ PrintError("IDE: Error getting CDROM capacity (%x)\n", cmd);
+ return -1;
+ }
+ break;
+
+
+ case 0x43: // read TOC
+ if (atapi_read_toc(dev, channel) == -1) {
+ PrintError("IDE: Error getting CDROM TOC (%x)\n", cmd);
+ return -1;
+ }
+ break;
+
+ case 0x46: // get configuration
+ if (atapi_get_config(dev, channel) == -1) {
+ PrintError("IDE: Error getting CDROM Configuration (%x)\n", cmd);
+ return -1;
+ }
+ break;
+
+ case 0x51: // read disk info
+ // no-op to keep the Linux CD-ROM driver happy
+ PrintDebug("Error: Read disk info no-op to keep the Linux CD-ROM driver happy\n");
+ atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
+ ide_raise_irq(dev, channel);
+ break;
+
+
+
+ case 0xa8: // read(12)
+
+
+ case 0x1b: // start/stop drive
+ case 0xbd: // mechanism status
+ case 0x12: // inquiry
+
+ case 0xbe: // read cd
+
+
+
+ case 0x2b: // seek
+ case 0x1e: // lock door
+ case 0x42: // read sub-channel
+
+
+
+ case 0x55: // mode select
+ case 0xa6: // load/unload cd
+ case 0x4b: // pause/resume
+ case 0x45: // play audio
+ case 0x47: // play audio msf
+ case 0xbc: // play cd
+ case 0xb9: // read cd msf
+ case 0x44: // read header
+ case 0xba: // scan
+ case 0xbb: // set cd speed
+ case 0x4e: // stop play/scan
+
+ case 0x4a: // ???
+ default:
+ PrintError("Unhandled ATAPI command %x\n", cmd);
+ atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_INV_CMD_FIELD);
+ ide_raise_irq(dev, channel);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void atapi_identify_device(struct ide_drive * drive) {
+ struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf);
+ const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
+ const char* firmware = "ALPHA1 ";
+
+ drive->transfer_length = 512;
+ drive->transfer_index = 0;
+
+
+ memset(drive_id->buf, 0, sizeof(drive_id->buf));
+
+ drive_id->fixed_drive = 1;
+ drive_id->removable_media = 1;
+
+ // Black magic...
+ drive_id->disk_speed1 = 1;
+ drive_id->disk_speed3 = 1;
+
+ drive_id->cdrom_flag = 1;
+
+ // These buffers do not contain a terminating "\0"
+ memcpy(drive_id->serial_num, serial_number, strlen(serial_number));
+ memcpy(drive_id->firmware_rev, firmware, strlen(firmware));
+ memcpy(drive_id->model_num, drive->model, 40);
+
+ // 32 bits access
+ drive_id->dword_io = 1;
+
+ // enable DMA access
+ drive_id->dma_enable = 1;
+
+ // enable LBA access
+ drive_id->lba_enable = 1;
+
+ drive_id->rw_multiples = 0x80ff;
+
+ // words 64-70, 54-58 valid
+ drive_id->field_valid = 0x0007; // DMA + pkg cmd valid
+
+ // copied from CFA540A
+ // drive_id->buf[63] = 0x0103; // variable (DMA stuff)
+ drive_id->buf[63] = 0x0000; // variable (DMA stuff)
+ // drive_id->buf[64] = 0x0001; // PIO
+ drive_id->buf[65] = 0x00b4;
+ drive_id->buf[66] = 0x00b4;
+ drive_id->buf[67] = 0x012c;
+ drive_id->buf[68] = 0x00b4;
+
+ drive_id->buf[71] = 30; // faked
+ drive_id->buf[72] = 30; // faked
+
+ // drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
+ drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6
+
+ drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported;
+}
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#ifndef __DEVICES_IDE_TYPES_H__
+#define __DEVICES_IDE_TYPES_H__
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_types.h>
+
+
+struct ide_error_reg {
+ union {
+ uint8_t val;
+ struct {
+ uint_t addr_mark_nf : 1;
+ uint_t track0_nf : 1;
+ uint_t abort : 1;
+ uint_t rsvd0 : 1;
+ uint_t ID_nf : 1;
+ uint_t rsvd1 : 1;
+ uint_t data_error : 1;
+ uint_t bad_block : 1;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+struct ide_drive_head_reg {
+ union {
+ uint8_t val;
+ struct {
+ uint_t head_num : 4;
+ uint_t drive_sel : 1;
+ uint_t rsvd1 : 1;
+ uint_t lba_mode : 1;
+ uint_t rsvd2 : 1;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+struct ide_status_reg {
+ union {
+ uint8_t val;
+ struct {
+ uint_t error : 1;
+ uint_t index : 1;
+ uint_t corrected : 1;
+ uint_t data_req : 1;
+ uint_t seek_complete : 1;
+ uint_t write_fault : 1;
+ uint_t ready : 1;
+ uint_t busy : 1;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct ide_ctrl_reg {
+ union {
+ uint8_t val;
+ struct {
+ uint_t rsvd0 : 1;
+ uint_t irq_disable : 1;
+ uint_t soft_reset : 1;
+ uint_t rsvd1 : 5;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct ide_features_reg {
+ union {
+ uint8_t val;
+ uint8_t dma; // 1 == DMA, 0 = PIO
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct ide_dma_cmd_reg {
+ union {
+ uint8_t val;
+ struct {
+ uint8_t start : 1;
+ uint8_t rsvd1 : 2;
+ uint8_t read : 1;
+ uint8_t rsvd2 : 4;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+struct ide_dma_status_reg {
+ union {
+ uint8_t val;
+ struct {
+ uint8_t active : 1;
+ uint8_t err : 1;
+ uint8_t int_gen : 1;
+ uint8_t rsvd1 : 4;
+ uint8_t prd_int_status : 1;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct ide_dma_prd {
+ uint32_t base_addr;
+ uint16_t size;
+ uint16_t rsvd : 15;
+ uint8_t end_of_table : 1;
+} __attribute__((packed));
+
+
+
+typedef enum {IDE_CTRL_NOT_SPECIFIED,
+ IDE_CTRL_SINGLE_PORT,
+ IDE_CTRL_DUAL_PORT,
+ IDE_CTRL_DUAL_PORT_CACHE} ide_controller_type;
+
+struct ide_drive_id {
+ union {
+ uint16_t buf[256];
+ struct {
+ // 0
+ uint_t rsvd1 : 1;
+ uint_t hard_sectors : 1;
+ uint_t no_soft_sectors : 1;
+ uint_t no_mfm_enc : 1;
+ uint_t head_switch_time : 1;
+ uint_t spnd_mot_ctrl : 1;
+ uint_t fixed_drive : 1;
+ uint_t removable_media : 1;
+ uint_t disk_speed1 : 1;
+ uint_t disk_speed2 : 1;
+ uint_t disk_speed3 : 1;
+ uint_t rpm_tolerance : 1;
+ uint_t data_strobe_offset : 1;
+ uint_t track_offset_option : 1;
+ uint_t fmt_speed_tol : 1;
+ uint_t cdrom_flag : 1;
+
+ // 1
+ uint16_t num_cylinders;
+
+ // 2
+ uint16_t rsvd2;
+
+ // 3
+ uint16_t num_heads;
+ // 4
+ uint16_t bytes_per_track;
+ // 5
+ uint16_t bytes_per_sector;
+ // 6
+ uint16_t sectors_per_track;
+
+ // 7
+ uint16_t sector_gap;
+
+ // 8
+ uint8_t phase_lock_bytes;
+ uint8_t rsvd3;
+
+ // 9
+ uint16_t num_vendor_wds;
+
+ // 10
+ uint8_t serial_num[20]; // right aligned, padded with 0x20
+
+ // 20
+ uint16_t controller_type;
+
+ // 21
+ uint16_t buffer_size; // in 512 byte chunks
+
+ // 22
+ uint16_t num_ecc_bytes;
+
+ // 23
+ uint8_t firmware_rev[8]; // space padded
+
+ // 27
+ uint8_t model_num[40]; // space padded
+
+ // 47
+ uint16_t rw_multiples;
+
+ // 48
+ uint16_t dword_io;
+
+ // 49
+ uint8_t rsvd4;
+ uint8_t dma_enable : 1;
+ uint8_t lba_enable : 1;
+ uint8_t IORDYsw : 1;
+ uint8_t IORDYsup : 1;
+ uint8_t rsvd5 : 4;
+
+
+ // 50
+ uint16_t rsvd6;
+
+ // 51
+ uint16_t min_PIO_cycle; // 0=slow, 1=medium, 2=fast
+ // 52
+ uint16_t min_DMA_cycle; // 0=slow, 1=medium, 2=fast
+
+ // 53
+ uint16_t field_valid; // 2: ultra_ok word 88
+ // 1: eide_ok words 64-70
+ // 0: cur_ok words 54-58
+ // 54
+ uint16_t cur_cyls;
+ // 55
+ uint16_t cur_heads;
+ // 56
+ uint16_t cur_sectors;
+ // 57
+ uint16_t cur_capacity0;
+ // 58
+ uint16_t cur_capacity1;
+
+ // 59
+ uint8_t cur_mult_sect_cnt;
+ uint8_t mult_sect_valid; // bit0==0: valid
+
+ // 60
+ uint32_t lba_capacity;
+
+ // 62
+ uint16_t dma_lword;
+ // 63
+ uint16_t dma_mword;
+
+ // 64
+ uint16_t eide_pio_modes; // 0: (mode 3), 1: (mode 4)
+ // 65
+ uint16_t eide_dma_min; /* min mword dma cycle time (ns) */
+ // 66
+ uint16_t eide_dma_time; /* recommended mword dma cycle time (ns) */
+ // 67
+ uint16_t eide_pio; /* min cycle time (ns), no IORDY */
+ // 68
+ uint16_t eide_pio_iordy; /* min cycle time (ns), with IORDY */
+
+ // 69
+ uint16_t rsvd7[6];
+
+ // 75
+ uint16_t queue_depth;
+
+ // 76
+ uint16_t rsvd8[4];
+
+ // 80
+ uint16_t major_rev_num;
+ // 81
+ uint16_t minor_rev_num;
+ // 82
+ uint16_t cmd_set_1; /* 15: Obsolete
+ * 14: NOP command
+ * 13: READ_BUFFER
+ * 12: WRITE_BUFFER
+ * 11: Obsolete
+ * 10: Host Protected Area
+ * 9: DEVICE Reset
+ * 8: SERVICE Interrupt
+ * 7: Release Interrupt
+ * 6: look-ahead
+ * 5: write cache
+ * 4: PACKET Command
+ * 3: Power Management Feature Set
+ * 2: Removable Feature Set
+ * 1: Security Feature Set
+ * 0: S
+ */
+
+ // 83
+ uint16_t cmd_set_2; /* 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13: FLUSH CACHE EXT
+ * 12: FLUSH CACHE
+ * 11: Device Configuration Overlay
+ * 10: 48-bit Address Feature Set
+ * 9: Automatic Acoustic Management
+ * 8: SET MAX security
+ * 7: reserved 1407DT PARTIES
+ * 6: SetF sub-command Power-Up
+ * 5: Power-Up in Standby Feature Set
+ * 4: Removable Media Notification
+ * 3: APM Feature Set
+ * 2: CFA Feature Set
+ * 1: READ/WRITE DMA QUEUED
+ * 0: Download MicroCode
+ */
+
+ // 84
+ uint16_t cfsse; /* cmd set-feature supported extensions
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:6 reserved
+ * 5: General Purpose Logging
+ * 4: Streaming Feature Set
+ * 3: Media Card Pass Through
+ * 2: Media Serial Number Valid
+ * 1: SMART selt-test supported
+ * 0: SMART error logging
+ */
+
+ // 85
+ uint16_t cfs_enable_1; /* command set-feature enabled
+ * 15: Obsolete
+ * 14: NOP command
+ * 13: READ_BUFFER
+ * 12: WRITE_BUFFER
+ * 11: Obsolete
+ * 10: Host Protected Area
+ * 9: DEVICE Reset
+ * 8: SERVICE Interrupt
+ * 7: Release Interrupt
+ * 6: look-ahead
+ * 5: write cache
+ * 4: PACKET Command
+ * 3: Power Management Feature Set
+ * 2: Removable Feature Set
+ * 1: Security Feature Set
+ * 0: SMART Feature Set
+ */
+ // 86
+ uint16_t cfs_enable_2; /* command set-feature enabled
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13: FLUSH CACHE EXT
+ * 12: FLUSH CACHE
+ * 11: Device Configuration Overlay
+ * 10: 48-bit Address Feature Set
+ * 9: Automatic Acoustic Management
+ * 8: SET MAX security
+ * 7: reserved 1407DT PARTIES
+ * 6: SetF sub-command Power-Up
+ * 5: Power-Up in Standby Feature Set
+ * 4: Removable Media Notification
+ * 3: APM Feature Set
+ * 2: CFA Feature Set
+ * 1: READ/WRITE DMA QUEUED
+ * 0: Download MicroCode
+ */
+ // 87
+ uint16_t csf_default; /* command set-feature default
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 13:6 reserved
+ * 5: General Purpose Logging enabled
+ * 4: Valid CONFIGURE STREAM executed
+ * 3: Media Card Pass Through enabled
+ * 2: Media Serial Number Valid
+ * 1: SMART selt-test supported
+ * 0: SMART error logging
+ */
+ // 88
+ uint16_t dma_ultra;
+ // 89
+ uint16_t trs_euc; /* time required for security erase */
+ // 90
+ uint16_t trs_Euc; /* time required for enhanced erase */
+ // 91
+ uint16_t cur_apm_values; /* current APM values */
+ // 92
+ uint16_t mprc; /* master password revision code */
+ // 93
+ uint16_t hw_config; /* hardware config (word 93)
+ * 15: Shall be ZERO
+ * 14: Shall be ONE
+ * 0: Shall be ONE
+ */
+ // 94
+ uint16_t acoustic;
+ // 95
+ uint16_t msrqs; /* min stream request size */
+ // 96
+ uint16_t sxfert; /* stream transfer time */
+ // 97
+ uint16_t sal; /* stream access latency */
+ // 98
+ uint32_t spg; /* stream performance granularity */
+ // 100
+ uint64_t lba_capacity_2; /* 48-bit total number of sectors */
+ // 104
+ uint16_t rsvd9[22];
+
+ // 126
+ uint16_t last_lun;
+ // 127
+ uint16_t feature_set; // Removable Media Notification
+
+ // 128
+ uint16_t dlf; /* device lock function
+ * 15:9 reserved
+ * 8 security level 1:max 0:high
+ * 7:6 reserved
+ * 5 enhanced erase
+ * 4 expire
+ * 3 frozen
+ * 2 locked
+ * 1 en/disabled
+ * 0 capability
+ */
+ // 129
+ uint16_t csfo; /* current set features options
+ * 15:4 reserved
+ * 3: auto reassign
+ * 2: reverting
+ * 1: read-look-ahead
+ * 0: write cache
+ */
+
+ // 130
+ uint16_t rsvd10[30];
+
+ // 160
+ uint16_t cfa_power;
+
+ // 161
+ uint16_t cfa[15];
+ // 176
+ uint16_t cur_media_ser_num[30];
+ // 206
+ uint16_t rsvd11[49];
+ // 255
+ uint16_t integrity; /* 15:8 Checksum
+ * 7:0 Signature
+ */
+
+
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+#endif // ! __V3VEE__
+
+#endif
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm.h>
+#include <devices/ide.h>
+#include <devices/pci.h>
+#include "ide-types.h"
+#include "atapi-types.h"
+
+#define PRI_DEFAULT_IRQ 14
+#define SEC_DEFAULT_IRQ 15
+
+
+#define PRI_DATA_PORT 0x1f0
+#define PRI_FEATURES_PORT 0x1f1
+#define PRI_SECT_CNT_PORT 0x1f2
+#define PRI_SECT_NUM_PORT 0x1f3
+#define PRI_CYL_LOW_PORT 0x1f4
+#define PRI_CYL_HIGH_PORT 0x1f5
+#define PRI_DRV_SEL_PORT 0x1f6
+#define PRI_CMD_PORT 0x1f7
+#define PRI_CTRL_PORT 0x3f6
+#define PRI_ADDR_REG_PORT 0x3f7
+
+#define SEC_DATA_PORT 0x170
+#define SEC_FEATURES_PORT 0x171
+#define SEC_SECT_CNT_PORT 0x172
+#define SEC_SECT_NUM_PORT 0x173
+#define SEC_CYL_LOW_PORT 0x174
+#define SEC_CYL_HIGH_PORT 0x175
+#define SEC_DRV_SEL_PORT 0x176
+#define SEC_CMD_PORT 0x177
+#define SEC_CTRL_PORT 0x376
+#define SEC_ADDR_REG_PORT 0x377
+
+
+#define PRI_DMA_CMD_PORT 0xc000
+#define PRI_DMA_STATUS_PORT 0xc002
+#define PRI_DMA_PRD_PORT0 0xc004
+#define PRI_DMA_PRD_PORT1 0xc005
+#define PRI_DMA_PRD_PORT2 0xc006
+#define PRI_DMA_PRD_PORT3 0xc007
+
+#define SEC_DMA_CMD_PORT 0xc008
+#define SEC_DMA_STATUS_PORT 0xc00a
+#define SEC_DMA_PRD_PORT0 0xc00c
+#define SEC_DMA_PRD_PORT1 0xc00d
+#define SEC_DMA_PRD_PORT2 0xc00e
+#define SEC_DMA_PRD_PORT3 0xc00f
+
+#define DATA_BUFFER_SIZE 2048
+
+static const char * ide_pri_port_strs[] = {"PRI_DATA", "PRI_FEATURES", "PRI_SECT_CNT", "PRI_SECT_NUM",
+ "PRI_CYL_LOW", "PRI_CYL_HIGH", "PRI_DRV_SEL", "PRI_CMD",
+ "PRI_CTRL", "PRI_ADDR_REG"};
+
+
+static const char * ide_sec_port_strs[] = {"SEC_DATA", "SEC_FEATURES", "SEC_SECT_CNT", "SEC_SECT_NUM",
+ "SEC_CYL_LOW", "SEC_CYL_HIGH", "SEC_DRV_SEL", "SEC_CMD",
+ "SEC_CTRL", "SEC_ADDR_REG"};
+
+static const char * ide_dma_port_strs[] = {"PRI_DMA_CMD", NULL,
+ "PRI_DMA_STATUS", NULL,
+ "PRI_DMA_PRD0", "PRI_DMA_PRD1",
+ "PRI_DMA_PRD2", "PRI_DMA_PRD3",
+ "SEC_DMA_CMD", NULL,
+ "SEC_DMA_STATUS", NULL,
+ "SEC_DMA_PRD0","SEC_DMA_PRD1",
+ "SEC_DMA_PRD2","SEC_DMA_PRD3"};
+
+
+
+static inline const char * io_port_to_str(uint16_t port) {
+ if ((port >= PRI_DATA_PORT) && (port <= PRI_CMD_PORT)) {
+ return ide_pri_port_strs[port - PRI_DATA_PORT];
+ } else if ((port >= SEC_DATA_PORT) && (port <= SEC_CMD_PORT)) {
+ return ide_sec_port_strs[port - SEC_DATA_PORT];
+ } else if ((port == PRI_CTRL_PORT) || (port == PRI_ADDR_REG_PORT)) {
+ return ide_pri_port_strs[port - PRI_CTRL_PORT + 8];
+ } else if ((port == SEC_CTRL_PORT) || (port == SEC_ADDR_REG_PORT)) {
+ return ide_sec_port_strs[port - SEC_CTRL_PORT + 8];
+ } else if ((port >= PRI_DMA_CMD_PORT) && (port <= SEC_DMA_PRD_PORT3)) {
+ return ide_dma_port_strs[port - PRI_DMA_CMD_PORT];
+ }
+ return NULL;
+}
+
+
+
+static const char * ide_dev_type_strs[] = {"HARDDISK", "CDROM", "NONE"};
+
+
+static inline const char * device_type_to_str(v3_ide_dev_type_t type) {
+ if (type > 2) {
+ return NULL;
+ }
+
+ return ide_dev_type_strs[type];
+}
+
+
+
+struct ide_cd_state {
+ struct atapi_sense_data sense;
+ uint_t current_lba;
+ uint8_t atapi_cmd;
+ struct atapi_error_recovery err_recovery;
+};
+
+struct ide_hd_state {
+
+};
+
+struct ide_drive {
+ // Command Registers
+
+ v3_ide_dev_type_t drive_type;
+
+ union {
+ struct v3_ide_cd_ops * cd_ops;
+ struct v3_ide_hd_ops * hd_ops;
+ };
+
+
+ union {
+ struct ide_cd_state cd_state;
+ struct ide_hd_state hd_state;
+ };
+
+ char model[41];
+
+ // Where we are in the data transfer
+ uint_t transfer_index;
+
+ // the length of a transfer
+ // calculated for easy access
+ uint_t transfer_length;
+
+
+ // We have a local data buffer that we use for IO port accesses
+ uint8_t data_buf[DATA_BUFFER_SIZE];
+
+
+ void * private_data;
+
+ union {
+ uint8_t sector_count; // 0x1f2,0x172
+ struct atapi_irq_flags irq_flags;
+ } __attribute__((packed));
+
+ union {
+ uint8_t sector_num; // 0x1f3,0x173
+ uint8_t lba0;
+ };
+
+ union {
+ uint16_t cylinder;
+ uint16_t lba12;
+
+
+ struct {
+ uint8_t cylinder_low; // 0x1f4,0x174
+ uint8_t cylinder_high; // 0x1f5,0x175
+ } __attribute__((packed));
+
+ struct {
+ uint8_t lba1;
+ uint8_t lba2;
+ } __attribute__((packed));
+
+
+ // The transfer length requested by the CPU
+ uint16_t req_len;
+ } __attribute__((packed));
+
+ struct ide_dma_cmd_reg dma_cmd;
+ struct ide_dma_status_reg dma_status;
+ uint32_t dma_prd_addr;
+
+};
+
+
+
+struct ide_channel {
+ struct ide_drive drives[2];
+
+ // Command Registers
+ struct ide_error_reg error_reg; // [read] 0x1f1,0x171
+
+ struct ide_features_reg features;
+
+ struct ide_drive_head_reg drive_head; // 0x1f6,0x176
+
+ struct ide_status_reg status; // [read] 0x1f7,0x177
+ uint8_t cmd_reg; // [write] 0x1f7,0x177
+
+ int irq; // this is temporary until we add PCI support
+
+ struct pci_device * pci_dev;
+
+ // Control Registers
+ struct ide_ctrl_reg ctrl_reg; // [write] 0x3f6,0x376
+};
+
+
+
+struct ide_internal {
+ struct ide_channel channels[2];
+ struct vm_device * pci;
+ struct pci_device * busmaster_pci;
+};
+
+
+
+static inline uint16_t be_to_le_16(const uint16_t val) {
+ uint8_t * buf = (uint8_t *)&val;
+ return (buf[0] << 8) | (buf[1]) ;
+}
+
+static inline uint16_t le_to_be_16(const uint16_t val) {
+ return be_to_le_16(val);
+}
+
+
+static inline uint32_t be_to_le_32(const uint32_t val) {
+ uint8_t * buf = (uint8_t *)&val;
+ return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+static inline uint32_t le_to_be_32(const uint32_t val) {
+ return be_to_le_32(val);
+}
+
+
+static inline int get_channel_index(ushort_t port) {
+ if (((port & 0xfff8) == 0x1f0) ||
+ ((port & 0xfffe) == 0x3f6) ||
+ ((port & 0xfff8) == 0xc000)) {
+ return 0;
+ } else if (((port & 0xfff8) == 0x170) ||
+ ((port & 0xfffe) == 0x376) ||
+ ((port & 0xfff8) == 0xc008)) {
+ return 1;
+ }
+
+ return -1;
+}
+
+static inline struct ide_channel * get_selected_channel(struct ide_internal * ide, ushort_t port) {
+ int channel_idx = get_channel_index(port);
+ return &(ide->channels[channel_idx]);
+}
+
+static inline struct ide_drive * get_selected_drive(struct ide_channel * channel) {
+ return &(channel->drives[channel->drive_head.drive_sel]);
+}
+
+
+static inline int is_lba_enabled(struct ide_channel * channel) {
+ return channel->drive_head.lba_mode;
+}
+
+
+static void ide_raise_irq(struct vm_device * dev, struct ide_channel * channel) {
+ if (channel->ctrl_reg.irq_disable == 0) {
+ v3_raise_irq(dev->vm, channel->irq);
+ }
+}
+
+
+static void drive_reset(struct ide_drive * drive) {
+ drive->sector_count = 0x01;
+ drive->sector_num = 0x01;
+
+ if (drive->drive_type == IDE_CDROM) {
+ drive->cylinder = 0xeb14;
+ } else {
+ drive->cylinder = 0x0000;
+ }
+
+
+ memset(drive->data_buf, 0, sizeof(drive->data_buf));
+ drive->transfer_index = 0;
+
+ // Send the reset signal to the connected device callbacks
+ // channel->drives[0].reset();
+ // channel->drives[1].reset();
+}
+
+static void channel_reset(struct ide_channel * channel) {
+
+ // set busy and seek complete flags
+ channel->status.val = 0x90;
+
+ // Clear errors
+ channel->error_reg.val = 0x01;
+
+ // clear commands
+ channel->cmd_reg = 0x00;
+
+ channel->ctrl_reg.irq_disable = 0;
+}
+
+static void channel_reset_complete(struct ide_channel * channel) {
+ channel->status.busy = 0;
+ channel->status.ready = 1;
+
+ channel->drive_head.head_num = 0;
+
+ drive_reset(&(channel->drives[0]));
+ drive_reset(&(channel->drives[1]));
+}
+
+
+static void ide_abort_command(struct vm_device * dev, struct ide_channel * channel) {
+ channel->status.val = 0x41; // Error + ready
+ channel->error_reg.val = 0x04; // No idea...
+
+ ide_raise_irq(dev, channel);
+}
+
+
+// Include the ATAPI interface handlers
+#include "atapi.h"
+
+
+static int write_dma_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ struct ide_channel * channel = get_selected_channel(ide, port);
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ if (length != 1) {
+ PrintError("IDE: Invalid Write length on IDE port %x\n", port);
+ return -1;
+ }
+
+ PrintDebug("IDE: Writing DMA Port %x (%s) (val=%x)\n", port, io_port_to_str(port), *(uint8_t *)src);
+
+ switch (port) {
+ case PRI_DMA_CMD_PORT:
+ case SEC_DMA_CMD_PORT:
+ drive->dma_cmd.val = *(uint8_t *)src;
+ break;
+
+ case PRI_DMA_STATUS_PORT:
+ case SEC_DMA_STATUS_PORT:
+ drive->dma_status.val = *(uint8_t *)src;
+ break;
+
+ case PRI_DMA_PRD_PORT0:
+ case PRI_DMA_PRD_PORT1:
+ case PRI_DMA_PRD_PORT2:
+ case PRI_DMA_PRD_PORT3:
+ case SEC_DMA_PRD_PORT0:
+ case SEC_DMA_PRD_PORT1:
+ case SEC_DMA_PRD_PORT2:
+ case SEC_DMA_PRD_PORT3: {
+ uint_t addr_index = port & 0x3;
+ uint8_t * addr_buf = (uint8_t *)&(drive->dma_prd_addr);
+
+ addr_buf[addr_index] = *(uint8_t *)src;
+ break;
+ }
+ default:
+ PrintError("IDE: Invalid DMA Port (%x)\n", port);
+ return -1;
+ }
+
+ return length;
+}
+
+
+static int read_dma_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ struct ide_channel * channel = get_selected_channel(ide, port);
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ if (length != 1) {
+ PrintError("IDE: Invalid Write length on IDE port %x\n", port);
+ return -1;
+ }
+
+
+
+ switch (port) {
+ case PRI_DMA_CMD_PORT:
+ case SEC_DMA_CMD_PORT:
+ *(uint8_t *)dst = drive->dma_cmd.val;
+ break;
+
+ case PRI_DMA_STATUS_PORT:
+ case SEC_DMA_STATUS_PORT:
+ *(uint8_t *)dst = drive->dma_status.val;
+ break;
+
+ case PRI_DMA_PRD_PORT0:
+ case PRI_DMA_PRD_PORT1:
+ case PRI_DMA_PRD_PORT2:
+ case PRI_DMA_PRD_PORT3:
+ case SEC_DMA_PRD_PORT0:
+ case SEC_DMA_PRD_PORT1:
+ case SEC_DMA_PRD_PORT2:
+ case SEC_DMA_PRD_PORT3: {
+ uint_t addr_index = port & 0x3;
+ uint8_t * addr_buf = (uint8_t *)&(drive->dma_prd_addr);
+
+ *(uint8_t *)dst = addr_buf[addr_index];
+ break;
+ }
+ default:
+ PrintError("IDE: Invalid DMA Port (%x)\n", port);
+ return -1;
+ }
+
+ PrintDebug("IDE: Reading DMA Port %x (%s) (val=%x)\n", port, io_port_to_str(port), *(uint8_t *)dst);
+
+ return length;
+}
+
+
+
+static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ struct ide_channel * channel = get_selected_channel(ide, port);
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ if (length != 1) {
+ PrintError("Invalid Write Length on IDE command Port %x\n", port);
+ return -1;
+ }
+
+ PrintDebug("IDE: Writing Command Port %x (%s) (val=%x)\n", port, io_port_to_str(port), *(uint8_t *)src);
+
+ channel->cmd_reg = *(uint8_t *)src;
+
+ switch (channel->cmd_reg) {
+
+ case 0xa0: // ATAPI Command Packet
+ if (drive->drive_type != IDE_CDROM) {
+ ide_abort_command(dev, channel);
+ }
+
+ drive->sector_count = 1;
+
+ channel->status.busy = 0;
+ channel->status.write_fault = 0;
+ channel->status.data_req = 1;
+ channel->status.error = 0;
+
+ // reset the data buffer...
+ drive->transfer_length = ATAPI_PACKET_SIZE;
+ drive->transfer_index = 0;
+
+ break;
+ case 0xa1: // ATAPI Identify Device Packet
+ atapi_identify_device(drive);
+
+ channel->error_reg.val = 0;
+ channel->status.val = 0x58; // ready, data_req, seek_complete
+
+ ide_raise_irq(dev, channel);
+ break;
+ case 0xec: // Identify Device
+ if (drive->drive_type != IDE_DISK) {
+ drive_reset(drive);
+
+ // JRL: Should we abort here?
+ ide_abort_command(dev, channel);
+ } else {
+ PrintError("IDE Disks currently not implemented\n");
+ return -1;
+ }
+ break;
+ default:
+ PrintError("Unimplemented IDE command (%x)\n", channel->cmd_reg);
+ return -1;
+ }
+
+ return length;
+}
+
+
+static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ struct ide_channel * channel = get_selected_channel(ide, port);
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ // PrintDebug("IDE: Writing Data Port %x (val=%x, len=%d)\n",
+ // port, *(uint32_t *)src, length);
+
+ memcpy(drive->data_buf + drive->transfer_index, src, length);
+ drive->transfer_index += length;
+
+ // Transfer is complete, dispatch the command
+ if (drive->transfer_index >= drive->transfer_length) {
+ switch (channel->cmd_reg) {
+ case 0x30: // Write Sectors
+ PrintError("Writing Data not yet implemented\n");
+ return -1;
+
+ case 0xa0: // ATAPI packet command
+ if (atapi_handle_packet(dev, channel) == -1) {
+ PrintError("Error handling ATAPI packet\n");
+ return -1;
+ }
+ break;
+ default:
+ PrintError("Unhandld IDE Command %x\n", channel->cmd_reg);
+ return -1;
+ }
+ }
+
+ return length;
+}
+
+
+static int read_hd_data(uint8_t * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel) {
+ PrintError("Harddrive data port read not implemented\n");
+ return -1;
+}
+
+
+
+static int read_cd_data(uint8_t * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+ int data_offset = drive->transfer_index % DATA_BUFFER_SIZE;
+ int req_offset = drive->transfer_index % drive->req_len;
+
+ if (drive->cd_state.atapi_cmd != 0x28) {
+ PrintDebug("IDE: Reading CD Data (len=%d) (req_len=%d)\n", length, drive->req_len);
+ }
+
+ if (drive->transfer_index >= drive->transfer_length) {
+ PrintError("Buffer Overrun... (xfer_len=%d) (cur_idx=%d) (post_idx=%d)\n",
+ drive->transfer_length, drive->transfer_index,
+ drive->transfer_index + length);
+ return -1;
+ }
+
+
+
+ if ((data_offset == 0) && (drive->transfer_index > 0)) {
+
+ if (drive->drive_type == IDE_CDROM) {
+ if (atapi_update_data_buf(dev, channel) == -1) {
+ PrintError("Could not update CDROM data buffer\n");
+ return -1;
+ }
+ } else {
+ PrintError("IDE Harddrives not implemented\n");
+ return -1;
+ }
+ }
+
+ memcpy(dst, drive->data_buf + data_offset, length);
+
+ drive->transfer_index += length;
+
+ if ((req_offset == 0) && (drive->transfer_index > 0)) {
+ if (drive->transfer_index < drive->transfer_length) {
+ // An increment is complete, but there is still more data to be transferred...
+
+ channel->status.data_req = 1;
+
+ drive->irq_flags.c_d = 0;
+
+ // Update the request length in the cylinder regs
+ if (atapi_update_req_len(dev, channel, drive->transfer_length - drive->transfer_index) == -1) {
+ PrintError("Could not update request length after completed increment\n");
+ return -1;
+ }
+ } else {
+ // This was the final read of the request
+ channel->status.data_req = 0;
+ channel->status.ready = 1;
+
+ drive->irq_flags.c_d = 1;
+ drive->irq_flags.rel = 0;
+ }
+
+ drive->irq_flags.io_dir = 1;
+ channel->status.busy = 0;
+
+ ide_raise_irq(dev, channel);
+ }
+
+ return length;
+}
+
+
+static int read_drive_id(uint8_t * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel) {
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ channel->status.busy = 0;
+ channel->status.ready = 1;
+ channel->status.write_fault = 0;
+ channel->status.seek_complete = 1;
+ channel->status.corrected = 0;
+ channel->status.error = 0;
+
+
+ memcpy(dst, drive->data_buf + drive->transfer_index, length);
+ drive->transfer_index += length;
+
+ if (drive->transfer_index >= drive->transfer_length) {
+ channel->status.data_req = 0;
+ }
+
+ return length;
+}
+
+
+static int ide_read_data_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ struct ide_channel * channel = get_selected_channel(ide, port);
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ // PrintDebug("IDE: Reading Data Port %x (len=%d)\n", port, length);
+
+ if ((channel->cmd_reg == 0xec) ||
+ (channel->cmd_reg == 0xa1)) {
+ return read_drive_id((uint8_t *)dst, length, dev, channel);
+ }
+
+ if (drive->drive_type == IDE_CDROM) {
+ if (read_cd_data((uint8_t *)dst, length, dev, channel) == -1) {
+ PrintError("IDE: Could not read CD Data\n");
+ return -1;
+ }
+ } else if (drive->drive_type == IDE_DISK) {
+ if (read_hd_data((uint8_t *)dst, length, dev, channel) == -1) {
+ PrintError("IDE: Could not read HD Data\n");
+ return -1;
+ }
+ } else {
+ memset((uint8_t *)dst, 0, length);
+ }
+
+ return length;
+}
+
+static int write_port_std(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ struct ide_channel * channel = get_selected_channel(ide, port);
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ if (length != 1) {
+ PrintError("Invalid Write length on IDE port %x\n", port);
+ return -1;
+ }
+
+ PrintDebug("IDE: Writing Standard Port %x (%s) (val=%x)\n", port, io_port_to_str(port), *(uint8_t *)src);
+
+
+ switch (port) {
+ // reset and interrupt enable
+ case PRI_CTRL_PORT:
+ case SEC_CTRL_PORT: {
+ struct ide_ctrl_reg * tmp_ctrl = (struct ide_ctrl_reg *)src;
+
+ // only reset channel on a 0->1 reset bit transition
+ if ((!channel->ctrl_reg.soft_reset) && (tmp_ctrl->soft_reset)) {
+ channel_reset(channel);
+ } else if ((channel->ctrl_reg.soft_reset) && (!tmp_ctrl->soft_reset)) {
+ channel_reset_complete(channel);
+ }
+
+ channel->ctrl_reg.val = tmp_ctrl->val;
+ break;
+ }
+ case PRI_FEATURES_PORT:
+ case SEC_FEATURES_PORT:
+ channel->features.val = *(uint8_t *)src;
+ break;
+
+ case PRI_SECT_CNT_PORT:
+ case SEC_SECT_CNT_PORT:
+ drive->sector_count = *(uint8_t *)src;
+ break;
+
+ case PRI_SECT_NUM_PORT:
+ case SEC_SECT_NUM_PORT:
+ drive->sector_num = *(uint8_t *)src;
+
+ case PRI_CYL_LOW_PORT:
+ case SEC_CYL_LOW_PORT:
+ drive->cylinder_low = *(uint8_t *)src;
+ break;
+
+ case PRI_CYL_HIGH_PORT:
+ case SEC_CYL_HIGH_PORT:
+ drive->cylinder_high = *(uint8_t *)src;
+ break;
+
+ case PRI_DRV_SEL_PORT:
+ case SEC_DRV_SEL_PORT: {
+ channel->drive_head.val = *(uint8_t *)src;
+
+ // make sure the reserved bits are ok..
+ // JRL TODO: check with new ramdisk to make sure this is right...
+ channel->drive_head.val |= 0xa0;
+
+ drive = get_selected_drive(channel);
+
+ // Selecting a non-present device is a no-no
+ if (drive->drive_type == IDE_NONE) {
+ PrintDebug("Attempting to select a non-present drive\n");
+ channel->error_reg.abort = 1;
+ channel->status.error = 1;
+ }
+
+ break;
+ }
+ default:
+ PrintError("IDE: Write to unknown Port %x\n", port);
+ return -1;
+ }
+ return length;
+}
+
+
+static int read_port_std(ushort_t port, void * dst, uint_t length, struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ struct ide_channel * channel = get_selected_channel(ide, port);
+ struct ide_drive * drive = get_selected_drive(channel);
+
+ if (length != 1) {
+ PrintError("Invalid Read length on IDE port %x\n", port);
+ return -1;
+ }
+
+ PrintDebug("IDE: Reading Standard Port %x (%s)\n", port, io_port_to_str(port));
+
+
+ if ((port == PRI_ADDR_REG_PORT) ||
+ (port == SEC_ADDR_REG_PORT)) {
+ // unused, return 0xff
+ *(uint8_t *)dst = 0xff;
+ return length;
+ }
+
+
+ // if no drive is present just return 0 + reserved bits
+ if (drive->drive_type == IDE_NONE) {
+ if ((port == PRI_DRV_SEL_PORT) ||
+ (port == SEC_DRV_SEL_PORT)) {
+ *(uint8_t *)dst = 0xa0;
+ } else {
+ *(uint8_t *)dst = 0;
+ }
+
+ return length;
+ }
+
+ switch (port) {
+
+ // This is really the error register.
+ case PRI_FEATURES_PORT:
+ case SEC_FEATURES_PORT:
+ *(uint8_t *)dst = channel->error_reg.val;
+ break;
+
+ case PRI_SECT_CNT_PORT:
+ case SEC_SECT_CNT_PORT:
+ *(uint8_t *)dst = drive->sector_count;
+ break;
+
+ case PRI_SECT_NUM_PORT:
+ case SEC_SECT_NUM_PORT:
+ *(uint8_t *)dst = drive->sector_num;
+ break;
+
+ case PRI_CYL_LOW_PORT:
+ case SEC_CYL_LOW_PORT:
+ *(uint8_t *)dst = drive->cylinder_low;
+ break;
+
+
+ case PRI_CYL_HIGH_PORT:
+ case SEC_CYL_HIGH_PORT:
+ *(uint8_t *)dst = drive->cylinder_high;
+ break;
+
+ case PRI_DRV_SEL_PORT:
+ case SEC_DRV_SEL_PORT: // hard disk drive and head register 0x1f6
+ *(uint8_t *)dst = channel->drive_head.val;
+ break;
+
+ case PRI_CTRL_PORT:
+ case SEC_CTRL_PORT:
+ case PRI_CMD_PORT:
+ case SEC_CMD_PORT:
+ // Something about lowering interrupts here....
+ *(uint8_t *)dst = channel->status.val;
+ break;
+
+ default:
+ PrintError("Invalid Port: %x\n", port);
+ return -1;
+ }
+
+ PrintDebug("\tVal=%x\n", *(uint8_t *)dst);
+
+ return length;
+}
+
+
+
+static void init_drive(struct ide_drive * drive) {
+
+ drive->sector_count = 0x01;
+ drive->sector_num = 0x01;
+ drive->cylinder = 0x0000;
+
+ drive->drive_type = IDE_NONE;
+
+ memset(drive->model, 0, sizeof(drive->model));
+
+ drive->transfer_index = 0;
+ drive->transfer_length = 0;
+ memset(drive->data_buf, 0, sizeof(drive->data_buf));
+
+ drive->dma_cmd.val = 0;
+ drive->dma_status.val = 0;
+ drive->dma_prd_addr = 0;
+
+ drive->private_data = NULL;
+ drive->cd_ops = NULL;
+}
+
+static void init_channel(struct ide_channel * channel) {
+ int i = 0;
+
+ channel->error_reg.val = 0x01;
+ channel->drive_head.val = 0x00;
+ channel->status.val = 0x00;
+ channel->cmd_reg = 0x00;
+ channel->ctrl_reg.val = 0x08;
+
+
+ for (i = 0; i < 2; i++) {
+ init_drive(&(channel->drives[i]));
+ }
+
+}
+
+/*
+static int pci_config_update(struct pci_device * pci_dev, uint_t reg_num, int length) {
+ PrintError("IDE does not handle PCI config updates\n");
+ return -1;
+}
+*/
+
+static int init_ide_state(struct vm_device * dev) {
+ struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+ struct v3_pci_bar bars[6];
+ struct pci_device * pci_dev = NULL;
+ int i, j;
+
+ for (i = 0; i < 2; i++) {
+ init_channel(&(ide->channels[i]));
+
+ // JRL: this is a terrible hack...
+ ide->channels[i].irq = PRI_DEFAULT_IRQ + i;
+
+ for (j = 0; j < 6; j++) {
+ bars[j].type = PCI_BAR_NONE;
+ }
+
+
+ bars[4].type = PCI_BAR_IO;
+ bars[4].default_base_port = PRI_DMA_CMD_PORT + (i * 0x8);
+ bars[4].num_ports = 8;
+ bars[4].io_read = read_dma_port;
+ bars[4].io_write = write_dma_port;
+
+ pci_dev = v3_pci_register_device(ide->pci, PCI_STD_DEVICE, 0, "V3_IDE", -1, bars,
+ NULL, NULL, NULL, dev);
+
+ if (pci_dev == NULL) {
+ PrintError("Failed to register IDE BUS %d with PCI\n", i);
+ return -1;
+ }
+
+ ide->channels[i].pci_dev = pci_dev;
+
+ pci_dev->config_header.vendor_id = 0x1095;
+ pci_dev->config_header.device_id = 0x0646;
+ pci_dev->config_header.revision = 0x8f07;
+ pci_dev->config_header.subclass = 0x01;
+ pci_dev->config_header.class = 0x01;
+ }
+
+
+
+ /* Register PIIX3 Busmaster PCI device */
+ for (j = 0; j < 6; j++) {
+ bars[j].type = PCI_BAR_NONE;
+ }
+
+ pci_dev = v3_pci_register_device(ide->pci, PCI_STD_DEVICE, 0, "PIIX3 IDE", -1, bars,
+ NULL, NULL, NULL, dev);
+
+
+ ide->busmaster_pci = pci_dev;
+
+ pci_dev->config_header.vendor_id = 0x8086;
+ pci_dev->config_header.device_id = 0x7010;
+ pci_dev->config_header.revision = 0x80;
+ pci_dev->config_header.subclass = 0x01;
+ pci_dev->config_header.class = 0x01;
+
+
+ return 0;
+}
+
+
+
+static int init_ide(struct vm_device * dev) {
+ //struct ide_internal * ide = (struct ide_internal *)(dev->private_data);
+
+ PrintDebug("IDE: Initializing IDE\n");
+
+ if (init_ide_state(dev) == -1) {
+ PrintError("Failed to initialize IDE state\n");
+ return -1;
+ }
+
+
+
+
+ v3_dev_hook_io(dev, PRI_DATA_PORT,
+ &ide_read_data_port, &write_data_port);
+ v3_dev_hook_io(dev, PRI_FEATURES_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, PRI_SECT_CNT_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, PRI_SECT_NUM_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, PRI_CYL_LOW_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, PRI_CYL_HIGH_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, PRI_DRV_SEL_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, PRI_CMD_PORT,
+ &read_port_std, &write_cmd_port);
+
+ v3_dev_hook_io(dev, SEC_DATA_PORT,
+ &ide_read_data_port, &write_data_port);
+ v3_dev_hook_io(dev, SEC_FEATURES_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, SEC_SECT_CNT_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, SEC_SECT_NUM_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, SEC_CYL_LOW_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, SEC_CYL_HIGH_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, SEC_DRV_SEL_PORT,
+ &read_port_std, &write_port_std);
+ v3_dev_hook_io(dev, SEC_CMD_PORT,
+ &read_port_std, &write_cmd_port);
+
+
+ v3_dev_hook_io(dev, PRI_CTRL_PORT,
+ &read_port_std, &write_port_std);
+
+ v3_dev_hook_io(dev, SEC_CTRL_PORT,
+ &read_port_std, &write_port_std);
+
+
+ v3_dev_hook_io(dev, SEC_ADDR_REG_PORT,
+ &read_port_std, &write_port_std);
+
+ v3_dev_hook_io(dev, PRI_ADDR_REG_PORT,
+ &read_port_std, &write_port_std);
+
+
+ /*
+
+ v3_dev_hook_io(dev, PRI_DMA_CMD_PORT,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, PRI_DMA_STATUS_PORT,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, PRI_DMA_PRD_PORT0,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, PRI_DMA_PRD_PORT0,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, PRI_DMA_PRD_PORT0,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, PRI_DMA_PRD_PORT0,
+ &read_dma_port, &write_dma_port);
+
+
+ v3_dev_hook_io(dev, SEC_DMA_CMD_PORT,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, SEC_DMA_STATUS_PORT,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, SEC_DMA_PRD_PORT0,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, SEC_DMA_PRD_PORT0,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, SEC_DMA_PRD_PORT0,
+ &read_dma_port, &write_dma_port);
+ v3_dev_hook_io(dev, SEC_DMA_PRD_PORT0,
+ &read_dma_port, &write_dma_port);
+ */
+ return 0;
+}
+
+
+static int deinit_ide(struct vm_device * dev) {
+ // unhook io ports....
+ // deregister from PCI?
+ return 0;
+}
+
+
+static struct vm_device_ops dev_ops = {
+ .init = init_ide,
+ .deinit = deinit_ide,
+ .reset = NULL,
+ .start = NULL,
+ .stop = NULL,
+};
+
+
+struct vm_device * v3_create_ide(struct vm_device * pci) {
+ struct ide_internal * ide = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal));
+ struct vm_device * device = v3_create_device("IDE", &dev_ops, ide);
+
+ ide->pci = pci;
+
+ PrintDebug("IDE: Creating IDE bus x 2\n");
+
+ return device;
+}
+
+
+
+
+
+int v3_ide_register_cdrom(struct vm_device * ide_dev,
+ uint_t bus_num,
+ uint_t drive_num,
+ char * dev_name,
+ struct v3_ide_cd_ops * ops,
+ void * private_data) {
+
+ struct ide_internal * ide = (struct ide_internal *)(ide_dev->private_data);
+ struct ide_channel * channel = NULL;
+ struct ide_drive * drive = NULL;
+
+ V3_ASSERT((bus_num >= 0) && (bus_num < 2));
+ V3_ASSERT((drive_num >= 0) && (drive_num < 2));
+
+ channel = &(ide->channels[bus_num]);
+ drive = &(channel->drives[drive_num]);
+
+ if (drive->drive_type != IDE_NONE) {
+ PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num);
+ return -1;
+ }
+
+ strncpy(drive->model, dev_name, sizeof(drive->model) - 1);
+
+ while (strlen((char *)(drive->model)) < 40) {
+ strcat((char*)(drive->model), " ");
+ }
+
+
+ drive->drive_type = IDE_CDROM;
+
+ drive->cd_ops = ops;
+
+ drive->private_data = private_data;
+
+ return 0;
+}
+
+
+int v3_ide_register_harddisk(struct vm_device * ide_dev,
+ uint_t bus_num,
+ uint_t drive_num,
+ char * dev_name,
+ struct v3_ide_hd_ops * ops,
+ void * private_data) {
+
+ struct ide_internal * ide = (struct ide_internal *)(ide_dev->private_data);
+ struct ide_channel * channel = NULL;
+ struct ide_drive * drive = NULL;
+
+ V3_ASSERT((bus_num >= 0) && (bus_num < 2));
+ V3_ASSERT((drive_num >= 0) && (drive_num < 2));
+
+ channel = &(ide->channels[bus_num]);
+ drive = &(channel->drives[drive_num]);
+
+ if (drive->drive_type != IDE_NONE) {
+ PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num);
+ return -1;
+ }
+
+ strncpy(drive->model, dev_name, sizeof(drive->model) - 1);
+
+ drive->drive_type = IDE_DISK;
+
+ drive->hd_ops = ops;
+
+ drive->private_data = private_data;
+
+ return 0;
+}
int reg_offset = port & 0x3;
uint8_t * reg_addr = ((uint8_t *)&(pci_state->addr_reg.val)) + reg_offset;
- PrintDebug("Reading PCI Address Port (%x): %x\n", port, pci_state->addr_reg.val);
+ PrintDebug("Reading PCI Address Port (%x): %x len=%d\n", port, pci_state->addr_reg.val, length);
if (length == 4) {
if (reg_offset != 0) {
PrintDebug("Writing PCI Address Port(%x): %x\n", port, pci_state->addr_reg.val);
-
return length;
}
static int data_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * vmdev) {
- struct pci_internal * pci_state = (struct pci_internal *)vmdev->private_data;;
+ struct pci_internal * pci_state = (struct pci_internal *)(vmdev->private_data);
struct pci_device * pci_dev = NULL;
uint_t reg_num = pci_state->addr_reg.reg_num + (port & 0x3);
int i;
+ if (pci_state->addr_reg.bus_num != 0) {
+ int i = 0;
+ for (i = 0; i < length; i++) {
+ *(uint8_t *)dst = 0xff;
+ }
+
+ return length;
+ }
+
PrintDebug("Reading PCI Data register. bus = %d, dev = %d, reg = %d (%x), cfg_reg = %x\n",
pci_state->addr_reg.bus_num,
pci_state->addr_reg.dev_num,
reg_num, reg_num,
pci_state->addr_reg.val);
-
pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
if (pci_dev == NULL) {
for (i = 0; i < length; i++) {
- *((uint8_t *)dst + i) = 0xff;
+ *(uint8_t *)((uint8_t *)dst + i) = 0xff;
}
return length;
}
for (i = 0; i < length; i++) {
- *((uint8_t *)dst + i) = pci_dev->config_space[reg_num + i];
+ *(uint8_t *)((uint8_t *)dst + i) = pci_dev->config_space[reg_num + i];
}
-
+
+ PrintDebug("\tVal=%x, len=%d\n", *(uint32_t *)dst, length);
+
return length;
}
}
+static int bar_update(struct pci_device * pci, int bar_num) {
+ PrintError("Bar Updates not handled (bar=%d)\n", bar_num);
+ return -1;
+}
+
+
static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_device * vmdev) {
struct pci_internal * pci_state = (struct pci_internal *)vmdev->private_data;
struct pci_device * pci_dev = NULL;
uint_t reg_num = pci_state->addr_reg.reg_num + (port & 0x3);
int i;
- PrintDebug("Writing PCI Data register. bus = %d, dev = %d, reg = %d (%x) addr_reg = %x\n",
+
+ if (pci_state->addr_reg.bus_num != 0) {
+ return length;
+ }
+
+ PrintDebug("Writing PCI Data register. bus = %d, dev = %d, reg = %d (%x) addr_reg = %x (val=%x, len=%d)\n",
pci_state->addr_reg.bus_num,
pci_state->addr_reg.dev_num,
reg_num, reg_num,
- pci_state->addr_reg.val);
+ pci_state->addr_reg.val,
+ *(uint32_t *)src, length);
pci_dev = get_device(&(pci_state->bus_list[0]), pci_state->addr_reg.dev_num);
uint_t cur_reg = reg_num + i;
if (is_cfg_reg_writable(pci_dev->config_header.header_type, cur_reg)) {
- pci_dev->config_space[cur_reg] = *((uint8_t *)src + i);
+ pci_dev->config_space[cur_reg] = *(uint8_t *)((uint8_t *)src + i);
if ((cur_reg >= 0x10) && (cur_reg < 0x28)) {
// BAR Reg
int bar_reg = (cur_reg & ~0x3) - 0x10;
+
+ pci_dev->bar_update_flag = 1;
+ pci_dev->bar[bar_reg].updated = 1;
+
+ PrintDebug("Updating BAR register\n");
- if (pci_dev->bar[bar_reg].bar_update) {
- pci_dev->bar_update_flag = 1;
- pci_dev->bar[bar_reg].updated = 1;
- }
} else if ((cur_reg >= 0x30) && (cur_reg < 0x34)) {
pci_dev->ext_rom_update_flag = 1;
} else if (cur_reg == 0x04) {
- // COMMAND update
- uint8_t command = *((uint8_t *)src + i);
-
- pci_dev->config_space[cur_reg] = command;
-
- if (pci_dev->cmd_update) {
- pci_dev->cmd_update(pci_dev, (command & 0x01), (command & 0x02));
- }
-
-
+ // COMMAND update
+ uint8_t command = *((uint8_t *)src + i);
+
+ pci_dev->config_space[cur_reg] = command;
+
+ if (pci_dev->cmd_update) {
+ pci_dev->cmd_update(pci_dev, (command & 0x01), (command & 0x02));
+ }
+
} else if (cur_reg == 0x0f) {
// BIST update
pci_dev->config_header.BIST = 0x00;
*(uint32_t *)(pci_dev->config_space + bar_offset) &= pci_dev->bar[i].mask;
- if (pci_dev->bar[i].bar_update) {
- pci_dev->bar[i].bar_update(pci_dev, i);
+ // bar_update
+ if (bar_update(pci_dev, i) == -1) {
+ PrintError("PCI Device %s: Bar update Error Bar=%d\n", pci_dev->name, i);
+ return -1;
}
+
pci_dev->bar[i].updated = 0;
}
}
for (i = 0; i < 6; i++) {
bars[i].type = PCI_BAR_NONE;
- bars[i].mem_hook = 0;
- bars[i].num_pages = 0;
- bars[i].bar_update = NULL;
}
pci_dev = v3_pci_register_device(dev, PCI_STD_DEVICE, 0, "i440FX", 0, bars,
-static void test_devices(struct vm_device * dev) {
- struct pci_device * pci_dev = NULL;
- struct v3_pci_bar bars[6];
- int i;
-
- for (i = 0; i < 6; i++) {
- bars[i].type = PCI_BAR_NONE;
- bars[i].mem_hook = 0;
- bars[i].num_pages = 0;
- bars[i].bar_update = NULL;
- }
-
-
- pci_dev = v3_pci_register_device(dev, PCI_STD_DEVICE, 0, "", 0, bars,
- NULL, NULL, NULL, NULL);
-
- pci_dev->config_header.vendor_id = 0x8086;
- pci_dev->config_header.device_id = 0x0101;
- pci_dev->config_header.revision = 0x0002;
- pci_dev->config_header.subclass = 0x01; // SubClass: host2pci
- pci_dev->config_header.class = 0x01; // Class: PCI bridge
-
- pci_dev = v3_pci_register_device(dev, PCI_STD_DEVICE, 0, "", 0, bars,
- NULL, NULL, NULL, NULL);
-
- pci_dev->config_header.vendor_id = 0x8086;
- pci_dev->config_header.device_id = 0x0101;
- pci_dev->config_header.revision = 0x0002;
- pci_dev->config_header.subclass = 0x00; // SubClass: host2pci
- pci_dev->config_header.class = 0x02; // Class: PCI bridge
-
-
-
-
-}
-
-
static void init_pci_busses(struct pci_internal * pci_state) {
int i;
PrintError("Could not intialize i440fx\n");
return -1;
}
-
- test_devices(dev);
PrintDebug("Sizeof config header=%d\n", (int)sizeof(struct pci_config_header));
int i = 0;
for (i = 0; i < 6; i++) {
- int bar_offset = 0x10 + 4 * i;
+ int bar_offset = 0x10 + (4 * i);
if (pci_dev->bar[i].type == PCI_BAR_IO) {
- pci_dev->bar[i].mask = 0x0000fffd;
- *(uint32_t *)(pci_dev->config_space + bar_offset) = 0x00000001;
+ int j = 0;
+ pci_dev->bar[i].mask = (~((pci_dev->bar[i].num_ports) - 1)) | 0x01;
+
+ *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].default_base_port & pci_dev->bar[i].mask;
+ *(uint32_t *)(pci_dev->config_space + bar_offset) |= 0x00000001;
+
+ for (j = 0; j < pci_dev->bar[i].num_ports; j++) {
+ // hook IO
+ if (v3_dev_hook_io(pci_dev->vm_dev, pci_dev->bar[i].default_base_port + j,
+ pci_dev->bar[i].io_read, pci_dev->bar[i].io_write) == -1) {
+ PrintError("Could not hook default io port %x\n", pci_dev->bar[i].default_base_port + j);
+ return -1;
+ }
+ }
+
} else if (pci_dev->bar[i].type == PCI_BAR_MEM32) {
pci_dev->bar[i].mask = ~((pci_dev->bar[i].num_pages << 12) - 1);
pci_dev->bar[i].mask |= 0xf; // preserve the configuration flags
-
- *(uint32_t *)(pci_dev->config_space + bar_offset) = 0x00000008;
-
- if (pci_dev->bar[i].mem_hook) {
- // clear the prefetchable flag...
- *(uint8_t *)(pci_dev->config_space + bar_offset) &= ~0x00000008;
+
+ *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].default_base_addr & pci_dev->bar[i].mask;
+
+ // hook memory
+ if (pci_dev->bar[i].mem_read) {
+ // full hook
+ v3_hook_full_mem(pci_dev->vm_dev->vm, pci_dev->bar[i].default_base_addr,
+ pci_dev->bar[i].default_base_addr + (pci_dev->bar[i].num_pages * PAGE_SIZE_4KB),
+ pci_dev->bar[i].mem_read, pci_dev->bar[i].mem_write, pci_dev->vm_dev);
+ } else if (pci_dev->bar[i].mem_write) {
+ // write hook
+ PrintError("Write hooks not supported for PCI devices\n");
+ return -1;
+ /*
+ v3_hook_write_mem(pci_dev->vm_dev->vm, pci_dev->bar[i].default_base_addr,
+ pci_dev->bar[i].default_base_addr + (pci_dev->bar[i].num_pages * PAGE_SIZE_4KB),
+ pci_dev->bar[i].mem_write, pci_dev->vm_dev);
+ */
+ } else {
+ // set the prefetchable flag...
+ *(uint8_t *)(pci_dev->config_space + bar_offset) |= 0x00000008;
}
+
} else if (pci_dev->bar[i].type == PCI_BAR_MEM16) {
PrintError("16 Bit memory ranges not supported (reg: %d)\n", i);
+ return -1;
} else if (pci_dev->bar[i].type == PCI_BAR_NONE) {
*(uint32_t *)(pci_dev->config_space + bar_offset) = 0x00000000;
} else {
PrintError("Invalid BAR type for bar #%d\n", i);
return -1;
}
-
-
}
return 0;
}
-
// if dev_num == -1, auto assign
struct pci_device * v3_pci_register_device(struct vm_device * pci,
pci_device_type_t dev_type,
pci_dev->priv_data = private_data;
-
+
//copy bars
for (i = 0; i < 6; i ++){
- pci_dev->bar[i].type = bars[i].type;
- pci_dev->bar[i].num_pages = bars[i].num_pages;
- pci_dev->bar[i].mem_hook = bars[i].mem_hook;
- pci_dev->bar[i].bar_update = bars[i].bar_update;
+ pci_dev->bar[i].type = bars[i].type;
+
+ if (pci_dev->bar[i].type == PCI_BAR_IO) {
+ pci_dev->bar[i].num_ports = bars[i].num_ports;
+ pci_dev->bar[i].default_base_port = bars[i].default_base_port;
+ pci_dev->bar[i].io_read = bars[i].io_read;
+ pci_dev->bar[i].io_write = bars[i].io_write;
+ } else {
+ pci_dev->bar[i].num_pages = bars[i].num_pages;
+ pci_dev->bar[i].default_base_addr = bars[i].default_base_addr;
+ pci_dev->bar[i].mem_read = bars[i].mem_read;
+ pci_dev->bar[i].mem_write = bars[i].mem_write;
+ }
}
if (init_bars(pci_dev) == -1) {
return NULL;
}
- pci_dev->cmd_update = cmd_update;
- pci_dev->ext_rom_update = ext_rom_update;
-
// add the device
add_device_to_bus(bus, pci_dev);
-
#ifdef DEBUG_PCI
pci_dump_state(pci_state);
#endif
case 0xec: // IDENTIFY DEVICE
case 0xa1:
{
-
-
controller->status.busy = 0;
controller->status.drive_ready = 1;
controller->status.write_fault = 0;
controller->status.seek_complete = 1;
controller->status.corrected_data = 0;
controller->status.err = 0;
-
+
/*
value32 = controller->buffer[index];
index++;
if (controller->buffer_index >= 512) {
controller->status.drq = 0;
}
-
+
return length;
}
case 0xa0: //send packet cmd
drive->id_drive[i] = 0;
}
- // now convert the id_drive array (native 256 word format) to
- // the controller buffer (512 bytes)
- Bit16u temp16;
- for (i = 0; i <= 255; i++) {
- temp16 = drive->id_drive[i];
- controller->buffer[i * 2] = temp16 & 0x00ff;
- controller->buffer[i * 2 + 1] = temp16 >> 8;
- }
return;
}
#include <devices/8254.h>
#include <devices/nvram.h>
#include <devices/generic.h>
-#include <devices/ramdisk.h>
-#include <devices/cdrom.h>
+#include <devices/ide.h>
+#include <devices/ram_cd.h>
#include <devices/bochs_debug.h>
#include <devices/os_debug.h>
#include <devices/apic.h>
static int setup_devices(struct guest_info * info, struct v3_vm_config * config_ptr) {
- struct vm_device * ramdisk = NULL;
- struct vm_device * cdrom = NULL;
-#ifdef DEBUG_PCI
+ struct vm_device * ide = NULL;
+ struct vm_device * ram_cd = NULL;
struct vm_device * pci = v3_create_pci();
-#endif
struct vm_device * nvram = v3_create_nvram();
//struct vm_device * timer = v3_create_timer();
struct vm_device * pic = v3_create_pic();
int use_ramdisk = config_ptr->use_ramdisk;
int use_generic = USE_GENERIC;
+ ide = v3_create_ide(pci);
if (use_ramdisk) {
PrintDebug("Creating Ramdisk\n");
- ramdisk = v3_create_ramdisk();
- cdrom = v3_create_cdrom(ramdisk, config_ptr->ramdisk, config_ptr->ramdisk_size);
+ ram_cd = v3_create_ram_cd(ide, 0, 0,
+ (addr_t)(config_ptr->ramdisk),
+ config_ptr->ramdisk_size);
}
generic = configure_generic(info, config_ptr);
}
-#ifdef DEBUG_PCI
+
v3_attach_device(info, pci);
-#endif
v3_attach_device(info, nvram);
//v3_attach_device(info, timer);
v3_attach_device(info, para_net);
+ v3_attach_device(info, ide);
+
if (use_ramdisk) {
- v3_attach_device(info, ramdisk);
- v3_attach_device(info, cdrom);
+ v3_attach_device(info, ram_cd);
}
if (use_generic) {