Merge pull request #819 from redox-os/cargo_workspace

Cargo workspace
This commit is contained in:
Jeremy Soller 2017-01-05 11:29:41 -07:00 committed by GitHub
commit 86c96b1b1d
67 changed files with 60 additions and 5779 deletions

9
.gitmodules vendored
View file

@ -61,3 +61,12 @@
[submodule "kernel"] [submodule "kernel"]
path = kernel path = kernel
url = https://github.com/redox-os/kernel.git url = https://github.com/redox-os/kernel.git
[submodule "drivers"]
path = drivers
url = https://github.com/redox-os/drivers.git
[submodule "bootloader"]
path = bootloader
url = https://github.com/redox-os/bootloader.git
[submodule "isolinux"]
path = isolinux
url = https://github.com/redox-os/isolinux.git

View file

@ -5,10 +5,10 @@ rust:
cache: cargo cache: cargo
os: os:
- linux - linux
- osx #- osx
matrix: #matrix:
allow_failures: # allow_failures:
- os: osx # - os: osx
dist: trusty dist: trusty
before_install: before_install:
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then - if [ "$TRAVIS_OS_NAME" == "linux" ]; then
@ -26,7 +26,7 @@ before_install:
script: script:
- make clean && - make clean &&
make update && make update &&
make build/harddrive.bin.gz build/livedisk.bin.gz build/livedisk.iso -j 2 make build/harddrive.bin.gz build/livedisk.bin.gz build/livedisk.iso
notifications: notifications:
email: false email: false
webhooks: http://37.139.9.28:54863/travis webhooks: http://37.139.9.28:54863/travis

34
Cargo.toml Normal file
View file

@ -0,0 +1,34 @@
[workspace]
members = [
"drivers/ahcid",
"drivers/bgad",
"drivers/e1000d",
"drivers/pcid",
"drivers/ps2d",
"drivers/rtl8168d",
"drivers/vesad",
"kernel",
"programs/acid",
"programs/binutils",
"programs/contain",
"programs/coreutils",
"programs/extrautils",
"programs/games",
"programs/init",
"programs/ion",
"programs/netutils",
"programs/orbutils",
"programs/pkgutils",
"programs/smith",
"programs/tar",
"programs/userutils",
"schemes/ethernetd",
"schemes/example",
"schemes/ipd",
"schemes/orbital",
"schemes/ptyd",
"schemes/randd",
"schemes/redoxfs",
"schemes/tcpd",
"schemes/udpd"
]

108
Makefile
View file

@ -37,38 +37,9 @@ iso: build/livedisk.iso
FORCE: FORCE:
clean: clean:
cargo clean
cargo clean --manifest-path rust/src/libstd/Cargo.toml cargo clean --manifest-path rust/src/libstd/Cargo.toml
cargo clean --manifest-path kernel/Cargo.toml -$(FUMOUNT) build/filesystem/ || true
cargo clean --manifest-path drivers/ahcid/Cargo.toml
cargo clean --manifest-path drivers/e1000d/Cargo.toml
cargo clean --manifest-path drivers/ps2d/Cargo.toml
cargo clean --manifest-path drivers/pcid/Cargo.toml
cargo clean --manifest-path drivers/rtl8168d/Cargo.toml
cargo clean --manifest-path drivers/vesad/Cargo.toml
cargo clean --manifest-path programs/acid/Cargo.toml
cargo clean --manifest-path programs/contain/Cargo.toml
cargo clean --manifest-path programs/init/Cargo.toml
cargo clean --manifest-path programs/ion/Cargo.toml
cargo clean --manifest-path programs/binutils/Cargo.toml
cargo clean --manifest-path programs/coreutils/Cargo.toml
cargo clean --manifest-path programs/extrautils/Cargo.toml
cargo clean --manifest-path programs/games/Cargo.toml
cargo clean --manifest-path programs/netutils/Cargo.toml
cargo clean --manifest-path programs/orbutils/Cargo.toml
cargo clean --manifest-path programs/pkgutils/Cargo.toml
cargo clean --manifest-path programs/userutils/Cargo.toml
cargo clean --manifest-path programs/smith/Cargo.toml
cargo clean --manifest-path programs/tar/Cargo.toml
cargo clean --manifest-path schemes/ethernetd/Cargo.toml
cargo clean --manifest-path schemes/example/Cargo.toml
cargo clean --manifest-path schemes/ipd/Cargo.toml
cargo clean --manifest-path schemes/orbital/Cargo.toml
cargo clean --manifest-path schemes/ptyd/Cargo.toml
cargo clean --manifest-path schemes/randd/Cargo.toml
cargo clean --manifest-path schemes/redoxfs/Cargo.toml
cargo clean --manifest-path schemes/tcpd/Cargo.toml
cargo clean --manifest-path schemes/udpd/Cargo.toml
-$(FUMOUNT) build/filesystem/
rm -rf initfs/bin rm -rf initfs/bin
rm -rf filesystem/bin filesystem/sbin filesystem/ui/bin rm -rf filesystem/bin filesystem/sbin filesystem/ui/bin
rm -rf build rm -rf build
@ -92,71 +63,8 @@ ref: FORCE
cargo run --manifest-path crates/docgen/Cargo.toml -- programs/extrautils/src/bin/ filesystem/ref/ cargo run --manifest-path crates/docgen/Cargo.toml -- programs/extrautils/src/bin/ filesystem/ref/
cargo run --manifest-path crates/docgen/Cargo.toml -- programs/netutils/src/ filesystem/ref/ cargo run --manifest-path crates/docgen/Cargo.toml -- programs/netutils/src/ filesystem/ref/
test:
cargo test --manifest-path rust/src/libstd/Cargo.toml
cargo test --manifest-path kernel/Cargo.toml
cargo test --manifest-path drivers/ahcid/Cargo.toml
cargo test --manifest-path drivers/e1000d/Cargo.toml
cargo test --manifest-path drivers/ps2d/Cargo.toml
cargo test --manifest-path drivers/pcid/Cargo.toml
cargo test --manifest-path drivers/rtl8168d/Cargo.toml
cargo test --manifest-path drivers/vesad/Cargo.toml
cargo test --manifest-path programs/acid/Cargo.toml
cargo test --manifest-path programs/contain/Cargo.toml
cargo test --manifest-path programs/init/Cargo.toml
cargo test --manifest-path programs/ion/Cargo.toml
cargo test --manifest-path programs/binutils/Cargo.toml
cargo test --manifest-path programs/coreutils/Cargo.toml
cargo test --manifest-path programs/extrautils/Cargo.toml
cargo test --manifest-path programs/games/Cargo.toml
cargo test --manifest-path programs/netutils/Cargo.toml
cargo test --manifest-path programs/orbutils/Cargo.toml
cargo test --manifest-path programs/pkgutils/Cargo.toml
cargo test --manifest-path programs/userutils/Cargo.toml
cargo test --manifest-path programs/smith/Cargo.toml
cargo test --manifest-path programs/tar/Cargo.toml
cargo test --manifest-path schemes/ethernetd/Cargo.toml
cargo test --manifest-path schemes/example/Cargo.toml
cargo test --manifest-path schemes/ipd/Cargo.toml
cargo test --manifest-path schemes/orbital/Cargo.toml
cargo test --manifest-path schemes/ptyd/Cargo.toml
cargo test --manifest-path schemes/randd/Cargo.toml
cargo test --manifest-path schemes/redoxfs/Cargo.toml
cargo test --manifest-path schemes/tcpd/Cargo.toml
cargo test --manifest-path schemes/udpd/Cargo.toml
update: update:
#cargo update --manifest-path rust/src/libstd/Cargo.toml cargo update
cargo update --manifest-path kernel/Cargo.toml
cargo update --manifest-path drivers/ahcid/Cargo.toml
cargo update --manifest-path drivers/e1000d/Cargo.toml
cargo update --manifest-path drivers/ps2d/Cargo.toml
cargo update --manifest-path drivers/pcid/Cargo.toml
cargo update --manifest-path drivers/rtl8168d/Cargo.toml
cargo update --manifest-path drivers/vesad/Cargo.toml
cargo update --manifest-path programs/acid/Cargo.toml
cargo update --manifest-path programs/contain/Cargo.toml
cargo update --manifest-path programs/init/Cargo.toml
cargo update --manifest-path programs/ion/Cargo.toml
cargo update --manifest-path programs/binutils/Cargo.toml
cargo update --manifest-path programs/coreutils/Cargo.toml
cargo update --manifest-path programs/extrautils/Cargo.toml
cargo update --manifest-path programs/games/Cargo.toml
cargo update --manifest-path programs/netutils/Cargo.toml
cargo update --manifest-path programs/orbutils/Cargo.toml
cargo update --manifest-path programs/pkgutils/Cargo.toml
cargo update --manifest-path programs/userutils/Cargo.toml
cargo update --manifest-path programs/smith/Cargo.toml
cargo update --manifest-path programs/tar/Cargo.toml
cargo update --manifest-path schemes/ethernetd/Cargo.toml
cargo update --manifest-path schemes/example/Cargo.toml
cargo update --manifest-path schemes/ipd/Cargo.toml
cargo update --manifest-path schemes/orbital/Cargo.toml
cargo update --manifest-path schemes/ptyd/Cargo.toml
cargo update --manifest-path schemes/randd/Cargo.toml
cargo update --manifest-path schemes/redoxfs/Cargo.toml
cargo update --manifest-path schemes/tcpd/Cargo.toml
cargo update --manifest-path schemes/udpd/Cargo.toml
pull: pull:
git pull --rebase --recurse-submodules git pull --rebase --recurse-submodules
@ -591,13 +499,13 @@ build/filesystem.bin: \
filesystem/bin/sh \ filesystem/bin/sh \
filesystem/bin/smith \ filesystem/bin/smith \
filesystem/bin/tar filesystem/bin/tar
-$(FUMOUNT) build/filesystem/ -$(FUMOUNT) build/filesystem/ || true
rm -rf $@ build/filesystem/ rm -rf $@ build/filesystem/
dd if=/dev/zero of=$@ bs=1048576 count=64 dd if=/dev/zero of=$@ bs=1048576 count=64
cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs-mkfs $@ cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs-mkfs $@
mkdir -p build/filesystem/ mkdir -p build/filesystem/
cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs
schemes/redoxfs/target/release/redoxfs $@ build/filesystem/ cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs -- $@ build/filesystem/
sleep 2 sleep 2
pgrep redoxfs pgrep redoxfs
cp -RL filesystem/* build/filesystem/ cp -RL filesystem/* build/filesystem/
@ -617,19 +525,19 @@ build/filesystem.bin: \
mkdir build/filesystem/tmp mkdir build/filesystem/tmp
chmod 1777 build/filesystem/tmp chmod 1777 build/filesystem/tmp
sync sync
-$(FUMOUNT) build/filesystem/ -$(FUMOUNT) build/filesystem/ || true
rm -rf build/filesystem/ rm -rf build/filesystem/
mount: FORCE mount: FORCE
mkdir -p build/filesystem/ mkdir -p build/filesystem/
cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs
schemes/redoxfs/target/release/redoxfs build/harddrive.bin build/filesystem/ cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs -- build/harddrive.bin build/filesystem/
sleep 2 sleep 2
pgrep redoxfs pgrep redoxfs
unmount: FORCE unmount: FORCE
sync sync
-$(FUMOUNT) build/filesystem/ -$(FUMOUNT) build/filesystem/ || true
rm -rf build/filesystem/ rm -rf build/filesystem/
wireshark: FORCE wireshark: FORCE

1
bootloader Submodule

@ -0,0 +1 @@
Subproject commit 7639aef32ed5ffd272701d955147b8b50aad53e0

View file

@ -1,17 +0,0 @@
interrupt_vector_table:
b . @ Reset
b .
b . @ SWI instruction
b .
b .
b .
b .
b .
.comm stack, 0x10000 @ Reserve 64k stack in the BSS
_start:
.globl _start
ldr sp, =stack+0x10000 @ Set up the stack
bl kstart @ Jump to the main function
1:
b 1b @ Halt

View file

@ -1,188 +0,0 @@
ORG 0x7C00
SECTION .text
USE16
boot: ; dl comes with disk
; initialize segment registers
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
; initialize stack
mov sp, 0x7C00
; initialize CS
push ax
push word .set_cs
retf
.set_cs:
; save disk number
mov [disk], dl
mov si, name
call print
call print_line
mov bx, (startup_start - boot) / 512
call print_num
call print_line
mov bx, startup_start
call print_num
call print_line
mov eax, (startup_start - boot) / 512
mov bx, startup_start
mov cx, (startup_end - startup_start) / 512
xor dx, dx
call load
mov si, finished
call print
call print_line
jmp startup
; load some sectors from disk to a buffer in memory
; buffer has to be below 1MiB
; IN
; ax: start sector
; bx: offset of buffer
; cx: number of sectors (512 Bytes each)
; dx: segment of buffer
; CLOBBER
; ax, bx, cx, dx, si
; TODO rewrite to (eventually) move larger parts at once
; if that is done increase buffer_size_sectors in startup-common to that (max 0x80000 - startup_end)
load:
cmp cx, 127
jbe .good_size
pusha
mov cx, 127
call load
popa
add ax, 127
add dx, 127 * 512 / 16
sub cx, 127
jmp load
.good_size:
mov [DAPACK.addr], eax
mov [DAPACK.buf], bx
mov [DAPACK.count], cx
mov [DAPACK.seg], dx
call print_dapack
mov dl, [disk]
mov si, DAPACK
mov ah, 0x42
int 0x13
jc error
ret
; store some sectors to disk from a buffer in memory
; buffer has to be below 1MiB
; IN
; ax: start sector
; bx: offset of buffer
; cx: number of sectors (512 Bytes each)
; dx: segment of buffer
; CLOBBER
; ax, bx, cx, dx, si
; TODO rewrite to (eventually) move larger parts at once
; if that is done increase buffer_size_sectors in startup-common to that (max 0x80000 - startup_end)
store:
cmp cx, 127
jbe .good_size
pusha
mov cx, 127
call store
popa
add ax, 127
add dx, 127 * 512 / 16
sub cx, 127
jmp store
.good_size:
mov [DAPACK.addr], eax
mov [DAPACK.buf], bx
mov [DAPACK.count], cx
mov [DAPACK.seg], dx
call print_dapack
mov dl, [disk]
mov si, DAPACK
mov ah, 0x43
int 0x13
jc error
ret
print_dapack:
mov bx, [DAPACK.addr + 2]
call print_num
mov bx, [DAPACK.addr]
call print_num
mov al, '#'
call print_char
mov bx, [DAPACK.count]
call print_num
mov al, ' '
call print_char
mov bx, [DAPACK.seg]
call print_num
mov al, ':'
call print_char
mov bx, [DAPACK.buf]
call print_num
jmp print_line
error:
mov bh, 0
mov bl, ah
call print_num
mov al, ' '
call print_char
mov si, errored
call print
call print_line
.halt:
cli
hlt
jmp .halt
%include "print16.asm"
name: db "Redox Loader - Stage One",0
errored: db "Could not read disk",0
finished: db "Redox Loader - Stage Two",0
disk: db 0
DAPACK:
db 0x10
db 0
.count: dw 0 ; int 13 resets this to # of blocks actually read/written
.buf: dw 0 ; memory buffer destination address (0:7c00)
.seg: dw 0 ; in memory page zero
.addr: dq 0 ; put the lba to read in this spot
times 510-($-$$) db 0
db 0x55
db 0xaa

View file

@ -1,18 +0,0 @@
SECTION .text
USE16
align 512, db 0
config:
.xres: dw 0
.yres: dw 0
times 512 - ($ - config) db 0
save_config:
mov eax, (config - boot) / 512
mov bx, config
mov cx, 1
xor dx, dx
call store
ret

View file

@ -1,46 +0,0 @@
attrib:
.present equ 1 << 7
.ring1 equ 1 << 5
.ring2 equ 1 << 6
.ring3 equ 1 << 5 | 1 << 6
.user equ 1 << 4
;user
.code equ 1 << 3
; code
.conforming equ 1 << 2
.readable equ 1 << 1
; data
.expand_down equ 1 << 2
.writable equ 1 << 1
.accessed equ 1 << 0
;system
; legacy
.tssAvailabe16 equ 0x1
.ldt equ 0x2
.tssBusy16 equ 0x3
.call16 equ 0x4
.task equ 0x5
.interrupt16 equ 0x6
.trap16 equ 0x7
.tssAvailabe32 equ 0x9
.tssBusy32 equ 0xB
.call32 equ 0xC
.interrupt32 equ 0xE
.trap32 equ 0xF
; long mode
.ldt32 equ 0x2
.tssAvailabe64 equ 0x9
.tssBusy64 equ 0xB
.call64 equ 0xC
.interrupt64 equ 0xE
.trap64 equ 0xF
flags:
.granularity equ 1 << 7
.available equ 1 << 4
;user
.default_operand_size equ 1 << 6
; code
.long_mode equ 1 << 5
; data
.reserved equ 1 << 5

View file

@ -1,8 +0,0 @@
struc GDTEntry
.limitl resw 1
.basel resw 1
.basem resb 1
.attribute resb 1
.flags__limith resb 1
.baseh resb 1
endstruc

View file

@ -1,21 +0,0 @@
%include "bootsector.asm"
startup_start:
%ifdef ARCH_i386
%include "startup-i386.asm"
%endif
%ifdef ARCH_x86_64
%include "startup-x86_64.asm"
%endif
align 512, db 0
startup_end:
kernel_file:
incbin "build/kernel/kernel"
align 512, db 0
.end:
.length equ kernel_file.end - kernel_file
.length_sectors equ .length / 512
incbin "build/filesystem.bin"

View file

@ -1,78 +0,0 @@
SECTION .text
USE16
initialize:
.fpu: ;enable fpu
mov eax, cr0
and al, 11110011b
or al, 00100010b
mov cr0, eax
mov eax, cr4
or eax, 0x200
mov cr4, eax
fninit
ret
.sse: ;enable sse
mov eax, cr4
or ax, 0000011000000000b
mov cr4, eax
ret
;PIT Frequency
;If using nanoseconds, to minimize drift, one should find a frequency as close to an integer nanosecond value in wavelength
;Divider Hz Nanoseconds Properties
;2685 444.38795779019242706393 2250286.00003631746492922946 Best For Context Switching
;5370 222.19397889509621353196 4500572.00007263492985856020
;21029 56.73981961418358774390 17624306.99991199998882825455
;23714 50.31549576902532962244 19874592.99994831745375667118
;26399 45.19798729749864262535 22124878.99998463491868476373
;29084 41.02536331545408701233 24375165.00002095238361424615
;31769 37.55804925136663623868 26625451.00005726984854313455
;34454 34.63115071302799868423 28875737.00009358731347639618
;50113 23.80982313305263437963 41999471.99993295237244784676
;52798 22.59899364874932131267 44249757.99996926983737931766
;55483 21.50535599492937776736 46500044.00000558730230583335 Lowest Drift
;58168 20.51268165772704350616 48750330.00004190476724037528
;60853 19.60760630809765610021 51000616.00007822223218031738
.pit:
;initialize the PIT
mov ax, 2685 ;this is the divider for the PIT
out 0x40, al
rol ax, 8
out 0x40, al
;DISABLED ;enable rtc interrupt
;mov al, 0xB
;out 0x70, al
;rol ax, 8
;in al, 0x71
;rol ax, 8
;out 0x70, al
;rol ax, 8
;or al, 0x40
;out 0x71, al
ret
.pic: ;sets up IRQs at int 20-2F
mov al, 0x11
out 0x20, al
out 0xA0, al
mov al, 0x20 ;IRQ0 vector
out 0x21, al
mov al, 0x28 ;IRQ8 vector
out 0xA1, al
mov al, 4
out 0x21, al
mov al, 2
out 0xA1, al
mov al, 1
out 0x21, al
out 0xA1, al
xor al, al ;no IRQ masks
out 0x21, al
out 0xA1, al
mov al, 0x20 ;reset PIC's
out 0xA0, al
out 0x20, al
ret

View file

@ -1,19 +0,0 @@
%include "bootsector.asm"
startup_start:
%ifdef ARCH_i386
%include "startup-i386.asm"
%endif
%ifdef ARCH_x86_64
%include "startup-x86_64.asm"
%endif
align 512, db 0
startup_end:
kernel_file:
incbin "build/kernel/kernel_live"
align 512, db 0
.end:
.length equ kernel_file.end - kernel_file
.length_sectors equ .length / 512

View file

@ -1,32 +0,0 @@
SECTION .text
USE16
;Generate a memory map at 0x500 to 0x5000 (available memory not used for kernel or bootloader)
memory_map:
.start equ 0x0500
.end equ 0x5000
.length equ .end - .start
xor eax, eax
mov di, .start
mov ecx, .length / 4 ; moving 4 Bytes at once
cld
rep stosd
mov di, .start
mov edx, 0x534D4150
xor ebx, ebx
.lp:
mov eax, 0xE820
mov ecx, 24
int 0x15
jc .done ; Error or finished
cmp ebx, 0
je .done ; Finished
add di, 24
cmp di, .end
jb .lp ; Still have buffer space
.done:
ret

View file

@ -1,65 +0,0 @@
SECTION .text
USE16
; provide function for printing in x86 real mode
; print a string and a newline
; IN
; si: points at zero-terminated String
; CLOBBER
; ax
print_line:
mov al, 13
call print_char
mov al, 10
jmp print_char
; print a string
; IN
; si: points at zero-terminated String
; CLOBBER
; ax
print:
cld
.loop:
lodsb
test al, al
jz .done
call print_char
jmp .loop
.done:
ret
; print a character
; IN
; al: character to print
; CLOBBER
; ah
print_char:
mov ah, 0x0e
int 0x10
ret
; print a number in hex
; IN
; bx: the number
; CLOBBER
; cx, ax
print_num:
mov cx, 4
.lp:
mov al, bh
shr al, 4
cmp al, 0xA
jb .below_0xA
add al, 'A' - 0xA - '0'
.below_0xA:
add al, '0'
call print_char
shl bx, 4
loop .lp
ret

View file

@ -1,110 +0,0 @@
SECTION .text
USE16
startup:
; enable A20-Line via IO-Port 92, might not work on all motherboards
in al, 0x92
or al, 2
out 0x92, al
; loading kernel to 1MiB
; move part of kernel to startup_end via bootsector#load and then copy it up
; repeat until all of the kernel is loaded
; buffersize in multiple of sectors (512 Bytes)
; min 1
; max (0x70000 - startup_end) / 512
buffer_size_sectors equ 127
; buffer size in Bytes
buffer_size_bytes equ buffer_size_sectors * 512
kernel_base equ 0x100000
; how often do we need to call load and move memory
mov ecx, kernel_file.length_sectors / buffer_size_sectors
mov eax, (kernel_file - boot) / 512
mov edi, kernel_base
cld
.lp:
; saving counter
push cx
; populating buffer
mov cx, buffer_size_sectors
mov bx, kernel_file
mov dx, 0x0
push edi
push eax
call load
; moving buffer
call unreal
pop eax
pop edi
mov esi, kernel_file
mov ecx, buffer_size_bytes / 4
a32 rep movsd
; preparing next iteration
add eax, buffer_size_sectors
pop cx
loop .lp
; load the part of the kernel that does not fill the buffer completely
mov cx, kernel_file.length_sectors % buffer_size_sectors
test cx, cx
jz finished_loading ; if cx = 0 => skip
mov bx, kernel_file
mov dx, 0x0
call load
; moving remnants of kernel
call unreal
mov esi, kernel_file
mov ecx, (kernel_file.length_sectors % buffer_size_bytes) / 4
a32 rep movsd
finished_loading:
call memory_map
call vesa
mov si, init_fpu_msg
call printrm
call initialize.fpu
mov si, init_sse_msg
call printrm
call initialize.sse
mov si, init_pit_msg
call printrm
call initialize.pit
mov si, init_pic_msg
call printrm
call initialize.pic
mov si, startup_arch_msg
call printrm
jmp startup_arch
%include "config.asm"
%include "descriptor_flags.inc"
%include "gdt_entry.inc"
%include "unreal.asm"
%include "memory_map.asm"
%include "vesa.asm"
%include "initialize.asm"
init_fpu_msg: db "Init FPU",13,10,0
init_sse_msg: db "Init SSE",13,10,0
init_pit_msg: db "Init PIT",13,10,0
init_pic_msg: db "Init PIC",13,10,0
startup_arch_msg: db "Startup Arch",13,10,0

View file

@ -1,148 +0,0 @@
%include "startup-common.asm"
startup_arch:
; load protected mode GDT and IDT
cli
lgdt [gdtr]
lidt [idtr]
; set protected mode bit of cr0
mov eax, cr0
or eax, 1
mov cr0, eax
; far jump to load CS with 32 bit segment
jmp gdt.kernel_code:protected_mode
USE32
protected_mode:
; load all the other segments with 32 bit data segments
mov eax, gdt.kernel_data
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
mov esp, 0x800000 - 128
mov eax, gdt.tss
ltr ax
;rust init
mov eax, [kernel_base + 0x18]
mov [interrupts.handler], eax
mov eax, gdtr
mov ebx, idtr
mov ecx, tss
int 255
.lp:
sti
hlt
jmp .lp
gdtr:
dw gdt.end + 1 ; size
dd gdt ; offset
gdt:
.null equ $ - gdt
dq 0
.kernel_code equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code | attrib.readable
at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size
at GDTEntry.baseh, db 0
iend
.kernel_data equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable
at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size
at GDTEntry.baseh, db 0
iend
.user_code equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.code | attrib.readable
at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size
at GDTEntry.baseh, db 0
iend
.user_data equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable
at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size
at GDTEntry.baseh, db 0
iend
.user_tls equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable
at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size
at GDTEntry.baseh, db 0
iend
.tss equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw (tss.end - tss) & 0xFFFF
at GDTEntry.basel, dw (tss-$$+0x7C00) & 0xFFFF
at GDTEntry.basem, db ((tss-$$+0x7C00) >> 16) & 0xFF
at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.tssAvailabe32
at GDTEntry.flags__limith, db ((tss.end - tss) >> 16) & 0xF
at GDTEntry.baseh, db ((tss-$$+0x7C00) >> 24) & 0xFF
iend
.end equ $ - gdt
struc TSS
.prev_tss resd 1 ;The previous TSS - if we used hardware task switching this would form a linked list.
.esp0 resd 1 ;The stack pointer to load when we change to kernel mode.
.ss0 resd 1 ;The stack segment to load when we change to kernel mode.
.esp1 resd 1 ;everything below here is unused now..
.ss1 resd 1
.esp2 resd 1
.ss2 resd 1
.cr3 resd 1
.eip resd 1
.eflags resd 1
.eax resd 1
.ecx resd 1
.edx resd 1
.ebx resd 1
.esp resd 1
.ebp resd 1
.esi resd 1
.edi resd 1
.es resd 1
.cs resd 1
.ss resd 1
.ds resd 1
.fs resd 1
.gs resd 1
.ldt resd 1
.trap resw 1
.iomap_base resw 1
endstruc
tss:
istruc TSS
at TSS.esp0, dd 0x800000 - 128
at TSS.ss0, dd gdt.kernel_data
at TSS.iomap_base, dw 0xFFFF
iend
.end:

View file

@ -1,179 +0,0 @@
trampoline:
.ready: dq 0
.cpu_id: dq 0
.page_table: dq 0
.stack_start: dq 0
.stack_end: dq 0
.code: dq 0
times 512 - ($ - trampoline) db 0
startup_ap:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
; initialize stack
mov sp, 0x7C00
call initialize.fpu
call initialize.sse
;cr3 holds pointer to PML4
mov edi, 0x70000
mov cr3, edi
;enable FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension
mov eax, cr4
or eax, 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4
mov cr4, eax
; load protected mode GDT
lgdt [gdtr]
mov ecx, 0xC0000080 ; Read from the EFER MSR.
rdmsr
or eax, 1 << 11 | 1 << 8 ; Set the Long-Mode-Enable and NXE bit.
wrmsr
;enabling paging and protection simultaneously
mov ebx, cr0
or ebx, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
mov cr0, ebx
; far jump to enable Long Mode and load CS with 64 bit segment
jmp gdt.kernel_code:long_mode_ap
%include "startup-common.asm"
startup_arch:
cli
; setting up Page Tables
; Identity Mapping first GB
mov ax, 0x7000
mov es, ax
xor edi, edi
xor eax, eax
mov ecx, 6 * 4096 / 4 ;PML4, PDP, 4 PD / moves 4 Bytes at once
cld
rep stosd
xor edi, edi
;Link first PML4 and second to last PML4 to PDP
mov DWORD [es:edi], 0x71000 | 1 << 1 | 1
mov DWORD [es:edi + 510*8], 0x71000 | 1 << 1 | 1
add edi, 0x1000
;Link last PML4 to PML4
mov DWORD [es:edi - 8], 0x70000 | 1 << 1 | 1
;Link first four PDP to PD
mov DWORD [es:edi], 0x72000 | 1 << 1 | 1
mov DWORD [es:edi + 8], 0x73000 | 1 << 1 | 1
mov DWORD [es:edi + 16], 0x74000 | 1 << 1 | 1
mov DWORD [es:edi + 24], 0x75000 | 1 << 1 | 1
add edi, 0x1000
;Link all PD's (512 per PDP, 2MB each)y
mov ebx, 1 << 7 | 1 << 1 | 1
mov ecx, 4*512
.setpd:
mov [es:edi], ebx
add ebx, 0x200000
add edi, 8
loop .setpd
xor ax, ax
mov es, ax
;cr3 holds pointer to PML4
mov edi, 0x70000
mov cr3, edi
;enable FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension
mov eax, cr4
or eax, 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4
mov cr4, eax
; load protected mode GDT
lgdt [gdtr]
mov ecx, 0xC0000080 ; Read from the EFER MSR.
rdmsr
or eax, 1 << 11 | 1 << 8 ; Set the Long-Mode-Enable and NXE bit.
wrmsr
;enabling paging and protection simultaneously
mov ebx, cr0
or ebx, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
mov cr0, ebx
; far jump to enable Long Mode and load CS with 64 bit segment
jmp gdt.kernel_code:long_mode
USE64
long_mode:
; load all the other segments with 64 bit data segments
mov rax, gdt.kernel_data
mov ds, rax
mov es, rax
mov fs, rax
mov gs, rax
mov ss, rax
mov rsp, 0xFFFFFF000009F000
;rust init
mov rax, [kernel_base + 0x18]
jmp rax
long_mode_ap:
mov rax, gdt.kernel_data
mov ds, rax
mov es, rax
mov fs, rax
mov gs, rax
mov ss, rax
mov rdi, [trampoline.cpu_id]
mov rsi, [trampoline.page_table]
mov rdx, [trampoline.stack_start]
mov rcx, [trampoline.stack_end]
lea rsp, [rcx - 256]
mov rax, [trampoline.code]
mov qword [trampoline.ready], 1
jmp rax
gdtr:
dw gdt.end + 1 ; size
dq gdt ; offset
gdt:
.null equ $ - gdt
dq 0
.kernel_code equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code
at GDTEntry.flags__limith, db flags.long_mode
at GDTEntry.baseh, db 0
iend
.kernel_data equ $ - gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0
at GDTEntry.basel, dw 0
at GDTEntry.basem, db 0
; AMD System Programming Manual states that the writeable bit is ignored in long mode, but ss can not be set to this descriptor without it
at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable
at GDTEntry.flags__limith, db 0
at GDTEntry.baseh, db 0
iend
.end equ $ - gdt

View file

@ -1,54 +0,0 @@
SECTION .text
USE16
; switch to unreal mode; ds and es can address up to 4GiB
unreal:
cli
lgdt [unreal_gdtr]
push es
push ds
mov eax, cr0 ; switch to pmode by
or al,1 ; set pmode bit
mov cr0, eax
jmp $+2
; http://wiki.osdev.org/Babystep7
; When this register given a "selector", a "segment descriptor cache register"
; is filled with the descriptor values, including the size (or limit). After
; the switch back to real mode, these values are not modified, regardless of
; what value is in the 16-bit segment register. So the 64k limit is no longer
; valid and 32-bit offsets can be used with the real-mode addressing rules
mov bx, unreal_gdt.data
mov es, bx
mov ds, bx
and al,0xFE ; back to realmode
mov cr0, eax ; by toggling bit again
pop ds
pop es
sti
ret
unreal_gdtr:
dw unreal_gdt.end + 1 ; size
dd unreal_gdt ; offset
unreal_gdt:
.null equ $ - unreal_gdt
dq 0
.data equ $ - unreal_gdt
istruc GDTEntry
at GDTEntry.limitl, dw 0xFFFF
at GDTEntry.basel, dw 0x0
at GDTEntry.basem, db 0x0
at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable
at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size
at GDTEntry.baseh, db 0x0
iend
.end equ $ - unreal_gdt

View file

@ -1,207 +0,0 @@
%include "vesa.inc"
SECTION .text
USE16
vesa:
.getcardinfo:
mov ax, 0x4F00
mov di, VBECardInfo
int 0x10
cmp ax, 0x4F
je .findmode
mov eax, 1
ret
.resetlist:
;if needed, reset mins/maxes/stuff
xor cx, cx
mov [.minx], cx
mov [.miny], cx
mov [config.xres], cx
mov [config.yres], cx
.findmode:
mov si, [VBECardInfo.videomodeptr]
mov ax, [VBECardInfo.videomodeptr+2]
mov fs, ax
sub si, 2
.searchmodes:
add si, 2
mov cx, [fs:si]
cmp cx, 0xFFFF
jne .getmodeinfo
cmp word [.goodmode], 0
je .resetlist
jmp .findmode
.getmodeinfo:
push esi
mov [.currentmode], cx
mov ax, 0x4F01
mov di, VBEModeInfo
int 0x10
pop esi
cmp ax, 0x4F
je .foundmode
mov eax, 1
ret
.foundmode:
;check minimum values, really not minimums from an OS perspective but ugly for users
cmp byte [VBEModeInfo.bitsperpixel], 32
jb .searchmodes
.testx:
mov cx, [VBEModeInfo.xresolution]
cmp word [config.xres], 0
je .notrequiredx
cmp cx, [config.xres]
je .testy
jmp .searchmodes
.notrequiredx:
cmp cx, [.minx]
jb .searchmodes
.testy:
mov cx, [VBEModeInfo.yresolution]
cmp word [config.yres], 0
je .notrequiredy
cmp cx, [config.yres]
jne .searchmodes ;as if there weren't enough warnings, USE WITH CAUTION
cmp word [config.xres], 0
jnz .setmode
jmp .testgood
.notrequiredy:
cmp cx, [.miny]
jb .searchmodes
.testgood:
mov cx, [.currentmode]
mov [.goodmode], cx
push esi
; call decshowrm
; mov al, ':'
; call charrm
mov cx, [VBEModeInfo.xresolution]
call decshowrm
mov al, 'x'
call charrm
mov cx, [VBEModeInfo.yresolution]
call decshowrm
mov al, '@'
call charrm
xor ch, ch
mov cl, [VBEModeInfo.bitsperpixel]
call decshowrm
mov si, .modeok
call printrm
xor ax, ax
int 0x16
pop esi
cmp al, 'y'
je .setmode
cmp al, 's'
je .savemode
jmp .searchmodes
.savemode:
mov cx, [VBEModeInfo.xresolution]
mov [config.xres], cx
mov cx, [VBEModeInfo.yresolution]
mov [config.yres], cx
call save_config
.setmode:
mov bx, [.currentmode]
cmp bx, 0
je .nomode
or bx, 0x4000
mov ax, 0x4F02
int 0x10
.nomode:
cmp ax, 0x4F
je .returngood
mov eax, 1
ret
.returngood:
xor eax, eax
ret
.minx dw 640
.miny dw 480
.modeok db ": Is this OK? (s)ave/(y)es/(n)o",10,13,0
.goodmode dw 0
.currentmode dw 0
;useful functions
decshowrm:
mov si, .number
.clear:
mov al, "0"
mov [si], al
inc si
cmp si, .numberend
jb .clear
dec si
call convertrm
mov si, .number
.lp:
lodsb
cmp si, .numberend
jae .end
cmp al, "0"
jbe .lp
.end:
dec si
call printrm
ret
.number times 7 db 0
.numberend db 0
convertrm:
dec si
mov bx, si ;place to convert into must be in si, number to convert must be in cx
.cnvrt:
mov si, bx
sub si, 4
.ten4: inc si
cmp cx, 10000
jb .ten3
sub cx, 10000
inc byte [si]
jmp .cnvrt
.ten3: inc si
cmp cx, 1000
jb .ten2
sub cx, 1000
inc byte [si]
jmp .cnvrt
.ten2: inc si
cmp cx, 100
jb .ten1
sub cx, 100
inc byte [si]
jmp .cnvrt
.ten1: inc si
cmp cx, 10
jb .ten0
sub cx, 10
inc byte [si]
jmp .cnvrt
.ten0: inc si
cmp cx, 1
jb .return
sub cx, 1
inc byte [si]
jmp .cnvrt
.return:
ret
printrm:
mov al, [si]
test al, al
jz .return
call charrm
inc si
jmp printrm
.return:
ret
charrm: ;char must be in al
mov bx, 7
mov ah, 0xE
int 10h
ret

View file

@ -1,90 +0,0 @@
ABSOLUTE 0x5000
VBECardInfo:
.signature resb 4
.version resw 1
.oemstring resd 1
.capabilities resd 1
.videomodeptr resd 1
.totalmemory resw 1
.oemsoftwarerev resw 1
.oemvendornameptr resd 1
.oemproductnameptr resd 1
.oemproductrevptr resd 1
.reserved resb 222
.oemdata resb 256
ABSOLUTE 0x5200
VBEModeInfo:
.attributes resw 1
.winA resb 1
.winB resb 1
.granularity resw 1
.winsize resw 1
.segmentA resw 1
.segmentB resw 1
.winfuncptr resd 1
.bytesperscanline resw 1
.xresolution resw 1
.yresolution resw 1
.xcharsize resb 1
.ycharsize resb 1
.numberofplanes resb 1
.bitsperpixel resb 1
.numberofbanks resb 1
.memorymodel resb 1
.banksize resb 1
.numberofimagepages resb 1
.unused resb 1
.redmasksize resb 1
.redfieldposition resb 1
.greenmasksize resb 1
.greenfieldposition resb 1
.bluemasksize resb 1
.bluefieldposition resb 1
.rsvdmasksize resb 1
.rsvdfieldposition resb 1
.directcolormodeinfo resb 1
.physbaseptr resd 1
.offscreenmemoryoffset resd 1
.offscreenmemsize resw 1
.reserved resb 206
VBE.ModeAttributes:
.available equ 1 << 0
.bios equ 1 << 2
.color equ 1 << 3
.graphics equ 1 << 4
.vgacompatible equ 1 << 5
.notbankable equ 1 << 6
.linearframebuffer equ 1 << 7
ABSOLUTE 0x5400
VBEEDID:
.header resb 8
.manufacturer resw 1
.productid resw 1
.serial resd 1
.manufactureweek resb 1
.manufactureyear resb 1
.version resb 1
.revision resb 1
.input resb 1
.horizontalsize resb 1
.verticalsize resb 1
.gamma resb 1
.displaytype resb 1
.chromaticity resb 10
.timingI resb 1
.timingII resb 1
.timingreserved resb 1
.standardtiming: resw 8 ;format: db (horizontal-248)/8, aspectratio | verticalfrequency - 60
.aspect.16.10 equ 0 ;mul horizontal by 10, shr 4 to get vertical resolution
.aspect.4.3 equ 1 << 6 ;mul horizontal by 3, shr 2 to get vertical resolution
.aspect.5.4 equ 2 << 6 ;shl horizontal by 2, div by 5 to get vertical resolution
.aspect.16.9 equ 3 << 6 ;mul horizontal by 9, shr by 4 to get vertical resolution
.descriptorblock1 resb 18
.descriptorblock2 resb 18
.descriptorblock3 resb 18
.descriptorblock4 resb 18
.extensionflag resb 1
.checksum resb 1

1
drivers Submodule

@ -0,0 +1 @@
Subproject commit 9eeade88606095a03ee3c285972b45d1c499a971

View file

@ -1,10 +0,0 @@
[package]
name = "ahcid"
version = "0.1.0"
[dependencies]
bitflags = "*"
dma = { path = "../../crates/dma/" }
io = { path = "../../crates/io/" }
spin = "*"
redox_syscall = { path = "../../syscall/" }

View file

@ -1,108 +0,0 @@
use std::ptr;
use dma::Dma;
use syscall::error::Result;
use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader};
pub struct Disk {
id: usize,
port: &'static mut HbaPort,
size: u64,
clb: Dma<[HbaCmdHeader; 32]>,
ctbas: [Dma<HbaCmdTable>; 32],
_fb: Dma<[u8; 256]>,
buf: Dma<[u8; 256 * 512]>
}
impl Disk {
pub fn new(id: usize, port: &'static mut HbaPort) -> Result<Self> {
let mut clb = Dma::zeroed()?;
let mut ctbas = [
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
];
let mut fb = Dma::zeroed()?;
let buf = Dma::zeroed()?;
port.init(&mut clb, &mut ctbas, &mut fb);
let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) };
Ok(Disk {
id: id,
port: port,
size: size,
clb: clb,
ctbas: ctbas,
_fb: fb,
buf: buf
})
}
pub fn id(&self) -> usize {
self.id
}
pub fn size(&self) -> u64 {
self.size
}
pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
let sectors = buffer.len()/512;
let mut sector: usize = 0;
while sectors - sector >= 255 {
if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) {
return Err(err);
}
unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); }
sector += 255;
}
if sector < sectors {
if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) {
return Err(err);
}
unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); }
sector += sectors - sector;
}
Ok(sector * 512)
}
pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
let sectors = buffer.len()/512;
let mut sector: usize = 0;
while sectors - sector >= 255 {
unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); }
if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
return Err(err);
}
sector += 255;
}
if sector < sectors {
unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); }
if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) {
return Err(err);
}
sector += sectors - sector;
}
Ok(sector * 512)
}
}

View file

@ -1,155 +0,0 @@
use io::Mmio;
#[repr(u8)]
pub enum FisType {
/// Register FIS - host to device
RegH2D = 0x27,
/// Register FIS - device to host
RegD2H = 0x34,
/// DMA activate FIS - device to host
DmaAct = 0x39,
/// DMA setup FIS - bidirectional
DmaSetup = 0x41,
/// Data FIS - bidirectional
Data = 0x46,
/// BIST activate FIS - bidirectional
Bist = 0x58,
/// PIO setup FIS - device to host
PioSetup = 0x5F,
/// Set device bits FIS - device to host
DevBits = 0xA1
}
#[repr(packed)]
pub struct FisRegH2D {
// DWORD 0
pub fis_type: Mmio<u8>, // FIS_TYPE_REG_H2D
pub pm: Mmio<u8>, // Port multiplier, 1: Command, 0: Control
pub command: Mmio<u8>, // Command register
pub featurel: Mmio<u8>, // Feature register, 7:0
// DWORD 1
pub lba0: Mmio<u8>, // LBA low register, 7:0
pub lba1: Mmio<u8>, // LBA mid register, 15:8
pub lba2: Mmio<u8>, // LBA high register, 23:16
pub device: Mmio<u8>, // Device register
// DWORD 2
pub lba3: Mmio<u8>, // LBA register, 31:24
pub lba4: Mmio<u8>, // LBA register, 39:32
pub lba5: Mmio<u8>, // LBA register, 47:40
pub featureh: Mmio<u8>, // Feature register, 15:8
// DWORD 3
pub countl: Mmio<u8>, // Count register, 7:0
pub counth: Mmio<u8>, // Count register, 15:8
pub icc: Mmio<u8>, // Isochronous command completion
pub control: Mmio<u8>, // Control register
// DWORD 4
pub rsv1: [Mmio<u8>; 4], // Reserved
}
#[repr(packed)]
pub struct FisRegD2H {
// DWORD 0
pub fis_type: Mmio<u8>, // FIS_TYPE_REG_D2H
pub pm: Mmio<u8>, // Port multiplier, Interrupt bit: 2
pub status: Mmio<u8>, // Status register
pub error: Mmio<u8>, // Error register
// DWORD 1
pub lba0: Mmio<u8>, // LBA low register, 7:0
pub lba1: Mmio<u8>, // LBA mid register, 15:8
pub lba2: Mmio<u8>, // LBA high register, 23:16
pub device: Mmio<u8>, // Device register
// DWORD 2
pub lba3: Mmio<u8>, // LBA register, 31:24
pub lba4: Mmio<u8>, // LBA register, 39:32
pub lba5: Mmio<u8>, // LBA register, 47:40
pub rsv2: Mmio<u8>, // Reserved
// DWORD 3
pub countl: Mmio<u8>, // Count register, 7:0
pub counth: Mmio<u8>, // Count register, 15:8
pub rsv3: [Mmio<u8>; 2], // Reserved
// DWORD 4
pub rsv4: [Mmio<u8>; 4], // Reserved
}
#[repr(packed)]
pub struct FisData {
// DWORD 0
pub fis_type: Mmio<u8>, // FIS_TYPE_DATA
pub pm: Mmio<u8>, // Port multiplier
pub rsv1: [Mmio<u8>; 2], // Reserved
// DWORD 1 ~ N
pub data: [Mmio<u8>; 252], // Payload
}
#[repr(packed)]
pub struct FisPioSetup {
// DWORD 0
pub fis_type: Mmio<u8>, // FIS_TYPE_PIO_SETUP
pub pm: Mmio<u8>, // Port multiplier, direction: 4 - device to host, interrupt: 2
pub status: Mmio<u8>, // Status register
pub error: Mmio<u8>, // Error register
// DWORD 1
pub lba0: Mmio<u8>, // LBA low register, 7:0
pub lba1: Mmio<u8>, // LBA mid register, 15:8
pub lba2: Mmio<u8>, // LBA high register, 23:16
pub device: Mmio<u8>, // Device register
// DWORD 2
pub lba3: Mmio<u8>, // LBA register, 31:24
pub lba4: Mmio<u8>, // LBA register, 39:32
pub lba5: Mmio<u8>, // LBA register, 47:40
pub rsv2: Mmio<u8>, // Reserved
// DWORD 3
pub countl: Mmio<u8>, // Count register, 7:0
pub counth: Mmio<u8>, // Count register, 15:8
pub rsv3: Mmio<u8>, // Reserved
pub e_status: Mmio<u8>, // New value of status register
// DWORD 4
pub tc: Mmio<u16>, // Transfer count
pub rsv4: [Mmio<u8>; 2], // Reserved
}
#[repr(packed)]
pub struct FisDmaSetup {
// DWORD 0
pub fis_type: Mmio<u8>, // FIS_TYPE_DMA_SETUP
pub pm: Mmio<u8>, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1
pub rsv1: [Mmio<u8>; 2], // Reserved
// DWORD 1&2
pub dma_buffer_id: Mmio<u64>, /* DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */
// DWORD 3
pub rsv3: Mmio<u32>, // More reserved
// DWORD 4
pub dma_buffer_offset: Mmio<u32>, // Byte offset into buffer. First 2 bits must be 0
// DWORD 5
pub transfer_count: Mmio<u32>, // Number of bytes to transfer. Bit 0 must be 0
// DWORD 6
pub rsv6: Mmio<u32>, // Reserved
}

View file

@ -1,417 +0,0 @@
use std::mem::size_of;
use std::ops::DerefMut;
use std::{ptr, u32};
use dma::Dma;
use io::{Io, Mmio};
use syscall::error::{Error, Result, EIO};
use super::fis::{FisType, FisRegH2D};
const ATA_CMD_READ_DMA_EXT: u8 = 0x25;
const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35;
const ATA_CMD_IDENTIFY: u8 = 0xEC;
const ATA_DEV_BUSY: u8 = 0x80;
const ATA_DEV_DRQ: u8 = 0x08;
const HBA_PORT_CMD_CR: u32 = 1 << 15;
const HBA_PORT_CMD_FR: u32 = 1 << 14;
const HBA_PORT_CMD_FRE: u32 = 1 << 4;
const HBA_PORT_CMD_ST: u32 = 1;
const HBA_PORT_IS_ERR: u32 = 1 << 30 | 1 << 29 | 1 << 28 | 1 << 27;
const HBA_SSTS_PRESENT: u32 = 0x3;
const HBA_SIG_ATA: u32 = 0x00000101;
const HBA_SIG_ATAPI: u32 = 0xEB140101;
const HBA_SIG_PM: u32 = 0x96690101;
const HBA_SIG_SEMB: u32 = 0xC33C0101;
fn pause() {
unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); }
}
#[derive(Debug)]
pub enum HbaPortType {
None,
Unknown(u32),
SATA,
SATAPI,
PM,
SEMB,
}
#[repr(packed)]
pub struct HbaPort {
pub clb: [Mmio<u32>; 2], // 0x00, command list base address, 1K-byte aligned
pub fb: [Mmio<u32>; 2], // 0x08, FIS base address, 256-byte aligned
pub is: Mmio<u32>, // 0x10, interrupt status
pub ie: Mmio<u32>, // 0x14, interrupt enable
pub cmd: Mmio<u32>, // 0x18, command and status
pub _rsv0: Mmio<u32>, // 0x1C, Reserved
pub tfd: Mmio<u32>, // 0x20, task file data
pub sig: Mmio<u32>, // 0x24, signature
pub ssts: Mmio<u32>, // 0x28, SATA status (SCR0:SStatus)
pub sctl: Mmio<u32>, // 0x2C, SATA control (SCR2:SControl)
pub serr: Mmio<u32>, // 0x30, SATA error (SCR1:SError)
pub sact: Mmio<u32>, // 0x34, SATA active (SCR3:SActive)
pub ci: Mmio<u32>, // 0x38, command issue
pub sntf: Mmio<u32>, // 0x3C, SATA notification (SCR4:SNotification)
pub fbs: Mmio<u32>, // 0x40, FIS-based switch control
pub _rsv1: [Mmio<u32>; 11], // 0x44 ~ 0x6F, Reserved
pub vendor: [Mmio<u32>; 4], // 0x70 ~ 0x7F, vendor specific
}
impl HbaPort {
pub fn probe(&self) -> HbaPortType {
if self.ssts.readf(HBA_SSTS_PRESENT) {
let sig = self.sig.read();
match sig {
HBA_SIG_ATA => HbaPortType::SATA,
HBA_SIG_ATAPI => HbaPortType::SATAPI,
HBA_SIG_PM => HbaPortType::PM,
HBA_SIG_SEMB => HbaPortType::SEMB,
_ => HbaPortType::Unknown(sig),
}
} else {
HbaPortType::None
}
}
pub fn start(&mut self) {
while self.cmd.readf(HBA_PORT_CMD_CR) {
pause();
}
self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true);
}
pub fn stop(&mut self) {
self.cmd.writef(HBA_PORT_CMD_ST, false);
while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) {
pause();
}
self.cmd.writef(HBA_PORT_CMD_FRE, false);
}
pub fn slot(&self) -> Option<u32> {
let slots = self.sact.read() | self.ci.read();
for i in 0..32 {
if slots & 1 << i == 0 {
return Some(i);
}
}
None
}
pub fn init(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32], fb: &mut Dma<[u8; 256]>) {
self.stop();
for i in 0..32 {
let cmdheader = &mut clb[i];
cmdheader.ctba.write(ctbas[i].physical() as u64);
cmdheader.prdtl.write(0);
}
self.clb[0].write(clb.physical() as u32);
self.clb[1].write((clb.physical() >> 32) as u32);
self.fb[0].write(fb.physical() as u32);
self.fb[1].write((fb.physical() >> 32) as u32);
let is = self.is.read();
self.is.write(is);
self.ie.write(0);
let serr = self.serr.read();
self.serr.write(serr);
// Disable power management
let sctl = self.sctl.read() ;
self.sctl.write(sctl | 7 << 8);
// Power on and spin up device
self.cmd.writef(1 << 2 | 1 << 1, true);
print!("{}", format!(" - AHCI init {:X}\n", self.cmd.read()));
}
pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32]) -> Option<u64> {
self.is.write(u32::MAX);
let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap();
if let Some(slot) = self.slot() {
let cmdheader = &mut clb[slot as usize];
cmdheader.cfl.write(((size_of::<FisRegH2D>() / size_of::<u32>()) as u8));
cmdheader.prdtl.write(1);
{
let cmdtbl = &mut ctbas[slot as usize];
ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::<HbaCmdTable>());
let prdt_entry = &mut cmdtbl.prdt_entry[0];
prdt_entry.dba.write(dest.physical() as u64);
prdt_entry.dbc.write(512 | 1);
}
{
let cmdfis = &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D);
cmdfis.fis_type.write(FisType::RegH2D as u8);
cmdfis.pm.write(1 << 7);
cmdfis.command.write(ATA_CMD_IDENTIFY);
cmdfis.device.write(0);
cmdfis.countl.write(1);
cmdfis.counth.write(0);
}
while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {
pause();
}
self.ci.writef(1 << slot, true);
self.start();
while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 {
pause();
}
self.stop();
if self.is.read() & HBA_PORT_IS_ERR != 0 {
print!("{}", format!("ERROR IS {:X} TFD {:X} SERR {:X}\n", self.is.read(), self.tfd.read(), self.serr.read()));
return None;
}
let mut serial = String::new();
for word in 10..20 {
let d = dest[word];
let a = ((d >> 8) as u8) as char;
if a != '\0' {
serial.push(a);
}
let b = (d as u8) as char;
if b != '\0' {
serial.push(b);
}
}
let mut firmware = String::new();
for word in 23..27 {
let d = dest[word];
let a = ((d >> 8) as u8) as char;
if a != '\0' {
firmware.push(a);
}
let b = (d as u8) as char;
if b != '\0' {
firmware.push(b);
}
}
let mut model = String::new();
for word in 27..47 {
let d = dest[word];
let a = ((d >> 8) as u8) as char;
if a != '\0' {
model.push(a);
}
let b = (d as u8) as char;
if b != '\0' {
model.push(b);
}
}
let mut sectors = (dest[100] as u64) |
((dest[101] as u64) << 16) |
((dest[102] as u64) << 32) |
((dest[103] as u64) << 48);
let lba_bits = if sectors == 0 {
sectors = (dest[60] as u64) | ((dest[61] as u64) << 16);
28
} else {
48
};
print!("{}", format!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB\n",
serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048));
Some(sectors * 512)
} else {
None
}
}
pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma<HbaCmdTable>; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<usize> {
if write {
//print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write));
}
assert!(sectors > 0 && sectors < 256);
self.is.write(u32::MAX);
if let Some(slot) = self.slot() {
if write {
//print!("{}", format!("SLOT {}\n", slot));
}
let cmdheader = &mut clb[slot as usize];
cmdheader.cfl.write(((size_of::<FisRegH2D>() / size_of::<u32>()) as u8) | if write { 1 << 7 | 1 << 6 } else { 0 });
cmdheader.prdtl.write(1);
{
let cmdtbl = &mut ctbas[slot as usize];
unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::<HbaCmdTable>()) };
let prdt_entry = &mut cmdtbl.prdt_entry[0];
prdt_entry.dba.write(buf.physical() as u64);
prdt_entry.dbc.write(((sectors * 512) as u32) | 1);
}
{
let cmdfis = unsafe { &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D) };
cmdfis.fis_type.write(FisType::RegH2D as u8);
cmdfis.pm.write(1 << 7);
if write {
cmdfis.command.write(ATA_CMD_WRITE_DMA_EXT);
} else {
cmdfis.command.write(ATA_CMD_READ_DMA_EXT);
}
cmdfis.lba0.write(block as u8);
cmdfis.lba1.write((block >> 8) as u8);
cmdfis.lba2.write((block >> 16) as u8);
cmdfis.device.write(1 << 6);
cmdfis.lba3.write((block >> 24) as u8);
cmdfis.lba4.write((block >> 32) as u8);
cmdfis.lba5.write((block >> 40) as u8);
cmdfis.countl.write(sectors as u8);
cmdfis.counth.write((sectors >> 8) as u8);
}
if write {
//print!("WAIT ATA_DEV_BUSY | ATA_DEV_DRQ\n");
}
while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {
pause();
}
if write {
//print!("{}", format!("WRITE CI {:X} in {:X}\n", 1 << slot, self.ci.read()));
}
self.ci.writef(1 << slot, true);
self.start();
if write {
//print!("{}", format!("WAIT CI {:X} in {:X}\n", 1 << slot, self.ci.read()));
}
while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 {
pause();
if write {
//print!("{}", format!("WAIT CI {:X} TFD {:X} IS {:X} CMD {:X} SERR {:X}\n", self.ci.read(), self.tfd.read(), self.is.read(), self.cmd.read(), self.serr.read()));
}
}
self.stop();
if self.is.read() & HBA_PORT_IS_ERR != 0 {
print!("{}", format!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}\n",
self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(),
self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(),
self.ci.read(), self.sntf.read(), self.fbs.read()));
self.is.write(u32::MAX);
return Err(Error::new(EIO));
}
if write {
//print!("{}", format!("SUCCESS {}\n", sectors));
}
Ok(sectors * 512)
} else {
print!("No Command Slots\n");
Err(Error::new(EIO))
}
}
}
#[repr(packed)]
pub struct HbaMem {
pub cap: Mmio<u32>, // 0x00, Host capability
pub ghc: Mmio<u32>, // 0x04, Global host control
pub is: Mmio<u32>, // 0x08, Interrupt status
pub pi: Mmio<u32>, // 0x0C, Port implemented
pub vs: Mmio<u32>, // 0x10, Version
pub ccc_ctl: Mmio<u32>, // 0x14, Command completion coalescing control
pub ccc_pts: Mmio<u32>, // 0x18, Command completion coalescing ports
pub em_loc: Mmio<u32>, // 0x1C, Enclosure management location
pub em_ctl: Mmio<u32>, // 0x20, Enclosure management control
pub cap2: Mmio<u32>, // 0x24, Host capabilities extended
pub bohc: Mmio<u32>, // 0x28, BIOS/OS handoff control and status
pub _rsv: [Mmio<u8>; 116], // 0x2C - 0x9F, Reserved
pub vendor: [Mmio<u8>; 96], // 0xA0 - 0xFF, Vendor specific registers
pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers
}
impl HbaMem {
pub fn init(&mut self) {
/*
self.ghc.writef(1, true);
while self.ghc.readf(1) {
pause();
}
*/
self.ghc.write(1 << 31 | 1 << 1);
print!("{}", format!(" - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}",
self.cap.read(), self.ghc.read(), self.is.read(), self.pi.read(),
self.vs.read(), self.cap2.read(), self.bohc.read()));
}
}
#[repr(packed)]
pub struct HbaPrdtEntry {
dba: Mmio<u64>, // Data base address
_rsv0: Mmio<u32>, // Reserved
dbc: Mmio<u32>, // Byte count, 4M max, interrupt = 1
}
#[repr(packed)]
pub struct HbaCmdTable {
// 0x00
cfis: [Mmio<u8>; 64], // Command FIS
// 0x40
_acmd: [Mmio<u8>; 16], // ATAPI command, 12 or 16 bytes
// 0x50
_rsv: [Mmio<u8>; 48], // Reserved
// 0x80
prdt_entry: [HbaPrdtEntry; 65536], // Physical region descriptor table entries, 0 ~ 65535
}
#[repr(packed)]
pub struct HbaCmdHeader {
// DW0
cfl: Mmio<u8>, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */
_pm: Mmio<u8>, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier
prdtl: Mmio<u16>, // Physical region descriptor table length in entries
// DW1
_prdbc: Mmio<u32>, // Physical region descriptor byte count transferred
// DW2, 3
ctba: Mmio<u64>, // Command table descriptor base address
// DW4 - 7
_rsv1: [Mmio<u32>; 4], // Reserved
}

View file

@ -1,35 +0,0 @@
use io::Io;
use self::disk::Disk;
use self::hba::{HbaMem, HbaPortType};
pub mod disk;
pub mod fis;
pub mod hba;
pub fn disks(base: usize, name: &str) -> Vec<Disk> {
unsafe { &mut *(base as *mut HbaMem) }.init();
let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read();
let ret: Vec<Disk> = (0..32)
.filter(|&i| pi & 1 << i as i32 == 1 << i as i32)
.filter_map(|i| {
let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i];
let port_type = port.probe();
print!("{}", format!("{}-{}: {:?}\n", name, i, port_type));
match port_type {
HbaPortType::SATA => {
match Disk::new(i, port) {
Ok(disk) => Some(disk),
Err(err) => {
print!("{}", format!("{}: {}\n", i, err));
None
}
}
}
_ => None,
}
})
.collect();
ret
}

View file

@ -1,86 +0,0 @@
#![feature(asm)]
#[macro_use]
extern crate bitflags;
extern crate dma;
extern crate io;
extern crate spin;
extern crate syscall;
use std::{env, usize};
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Result, Scheme};
use scheme::DiskScheme;
pub mod ahci;
pub mod scheme;
fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a str, RawFd)> {
if let Ok(fd) = syscall::open(&format!(":{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) {
Ok((name, fd))
} else {
syscall::open(&format!(":{}", fallback), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK)
.map(|fd| (fallback, fd))
}
}
fn main() {
let mut args = env::args().skip(1);
let mut name = args.next().expect("ahcid: no name provided");
name.push_str("_ahci");
let bar_str = args.next().expect("ahcid: no address provided");
let bar = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address");
let irq_str = args.next().expect("ahcid: no irq provided");
let irq = irq_str.parse::<u8>().expect("ahcid: failed to parse irq");
print!("{}", format!(" + AHCI {} on: {:X} IRQ: {}\n", name, bar, irq));
// Daemonize
if unsafe { syscall::clone(0).unwrap() } == 0 {
let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") };
{
let (_scheme_name, socket_fd) = create_scheme_fallback("disk", &name).expect("ahcid: failed to create disk scheme");
let mut socket = unsafe { File::from_raw_fd(socket_fd) };
syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme");
let mut irq_file = File::open(&format!("irq:{}", irq)).expect("ahcid: failed to open irq file");
let irq_fd = irq_file.as_raw_fd();
syscall::fevent(irq_fd, EVENT_READ).expect("ahcid: failed to fevent irq file");
let mut event_file = File::open("event:").expect("ahcid: failed to open event file");
let scheme = DiskScheme::new(ahci::disks(address, &name));
loop {
let mut event = Event::default();
if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 {
break;
}
if event.id == socket_fd {
loop {
let mut packet = Packet::default();
if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 {
break;
}
scheme.handle(&mut packet);
socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
}
} else if event.id == irq_fd {
let mut irq = [0; 8];
if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() {
//TODO : Test for IRQ
//irq_file.write(&irq).expect("ahcid: failed to write irq file");
}
} else {
println!("Unknown event {}", event.id);
}
}
}
unsafe { let _ = syscall::physunmap(address); }
}
}

View file

@ -1,166 +0,0 @@
use std::collections::BTreeMap;
use std::{cmp, str};
use std::fmt::Write;
use std::io::Read;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use spin::Mutex;
use syscall::{Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, Scheme, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET};
use ahci::disk::Disk;
#[derive(Clone)]
enum Handle {
//TODO: Make these enum variants normal tuples (), not nested tuples (())
List((Vec<u8>, usize)),
Disk((Arc<Mutex<Disk>>, usize))
}
pub struct DiskScheme {
disks: Box<[Arc<Mutex<Disk>>]>,
handles: Mutex<BTreeMap<usize, Handle>>,
next_id: AtomicUsize
}
impl DiskScheme {
pub fn new(disks: Vec<Disk>) -> DiskScheme {
let mut disk_arcs = vec![];
for disk in disks {
disk_arcs.push(Arc::new(Mutex::new(disk)));
}
DiskScheme {
disks: disk_arcs.into_boxed_slice(),
handles: Mutex::new(BTreeMap::new()),
next_id: AtomicUsize::new(0)
}
}
}
impl Scheme for DiskScheme {
fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid == 0 {
let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/');
if path_str.is_empty() {
if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT {
let mut list = String::new();
for i in 0..self.disks.len() {
write!(list, "{}\n", i).unwrap();
}
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.lock().insert(id, Handle::List((list.into_bytes(), 0)));
Ok(id)
} else {
Err(Error::new(EISDIR))
}
} else {
let i = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
if let Some(disk) = self.disks.get(i) {
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.lock().insert(id, Handle::Disk((disk.clone(), 0)));
Ok(id)
} else {
Err(Error::new(ENOENT))
}
}
} else {
Err(Error::new(EACCES))
}
}
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
let mut handles = self.handles.lock();
let new_handle = {
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
handle.clone()
};
let new_id = self.next_id.fetch_add(1, Ordering::SeqCst);
handles.insert(new_id, new_handle);
Ok(new_id)
}
fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> {
let handles = self.handles.lock();
match *handles.get(&id).ok_or(Error::new(EBADF))? {
Handle::List(ref handle) => {
stat.st_mode = MODE_DIR;
stat.st_size = handle.0.len() as u64;
Ok(0)
},
Handle::Disk(ref handle) => {
stat.st_mode = MODE_FILE;
stat.st_size = handle.0.lock().size();
Ok(0)
}
}
}
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
let mut handles = self.handles.lock();
match *handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::List(ref mut handle) => {
let count = (&handle.0[handle.1..]).read(buf).unwrap();
handle.1 += count;
Ok(count)
},
Handle::Disk(ref mut handle) => {
let mut disk = handle.0.lock();
let count = disk.read((handle.1 as u64)/512, buf)?;
handle.1 += count;
Ok(count)
}
}
}
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
let mut handles = self.handles.lock();
match *handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::List(_) => {
Err(Error::new(EBADF))
},
Handle::Disk(ref mut handle) => {
let mut disk = handle.0.lock();
let count = disk.write((handle.1 as u64)/512, buf)?;
handle.1 += count;
Ok(count)
}
}
}
fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
let mut handles = self.handles.lock();
match *handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::List(ref mut handle) => {
let len = handle.0.len() as usize;
handle.1 = match whence {
SEEK_SET => cmp::min(len, pos),
SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize,
SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize,
_ => return Err(Error::new(EINVAL))
};
Ok(handle.1)
},
Handle::Disk(ref mut handle) => {
let len = handle.0.lock().size() as usize;
handle.1 = match whence {
SEEK_SET => cmp::min(len, pos),
SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize,
SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize,
_ => return Err(Error::new(EINVAL))
};
Ok(handle.1)
}
}
}
fn close(&self, id: usize) -> Result<usize> {
let mut handles = self.handles.lock();
handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(0))
}
}

View file

@ -1,3 +0,0 @@
[package]
name = "bgad"
version = "0.1.0"

View file

@ -1,13 +0,0 @@
use std::env;
fn main() {
let mut args = env::args().skip(1);
let mut name = args.next().expect("bgad: no name provided");
name.push_str("_bga");
let bar_str = args.next().expect("bgad: no address provided");
let bar = usize::from_str_radix(&bar_str, 16).expect("bgad: failed to parse address");
print!("{}", format!(" + BGA {} on: {:X}\n", name, bar));
}

View file

@ -1,11 +0,0 @@
[package]
name = "e1000d"
version = "0.1.0"
[dependencies]
bitflags = "*"
dma = { path = "../../crates/dma/" }
event = { path = "../../crates/event/" }
io = { path = "../../crates/io/" }
netutils = { path = "../../programs/netutils/" }
redox_syscall = { path = "../../syscall/" }

View file

@ -1,346 +0,0 @@
use std::{cmp, mem, ptr, slice};
use dma::Dma;
use netutils::setcfg;
use syscall::error::{Error, EACCES, EWOULDBLOCK, Result};
use syscall::flag::O_NONBLOCK;
use syscall::scheme::Scheme;
const CTRL: u32 = 0x00;
const CTRL_LRST: u32 = 1 << 3;
const CTRL_ASDE: u32 = 1 << 5;
const CTRL_SLU: u32 = 1 << 6;
const CTRL_ILOS: u32 = 1 << 7;
const CTRL_VME: u32 = 1 << 30;
const CTRL_PHY_RST: u32 = 1 << 31;
const STATUS: u32 = 0x08;
const FCAL: u32 = 0x28;
const FCAH: u32 = 0x2C;
const FCT: u32 = 0x30;
const FCTTV: u32 = 0x170;
const ICR: u32 = 0xC0;
const IMS: u32 = 0xD0;
const IMS_TXDW: u32 = 1;
const IMS_TXQE: u32 = 1 << 1;
const IMS_LSC: u32 = 1 << 2;
const IMS_RXSEQ: u32 = 1 << 3;
const IMS_RXDMT: u32 = 1 << 4;
const IMS_RX: u32 = 1 << 6;
const IMS_RXT: u32 = 1 << 7;
const RCTL: u32 = 0x100;
const RCTL_EN: u32 = 1 << 1;
const RCTL_UPE: u32 = 1 << 3;
const RCTL_MPE: u32 = 1 << 4;
const RCTL_LPE: u32 = 1 << 5;
const RCTL_LBM: u32 = 1 << 6 | 1 << 7;
const RCTL_BAM: u32 = 1 << 15;
const RCTL_BSIZE1: u32 = 1 << 16;
const RCTL_BSIZE2: u32 = 1 << 17;
const RCTL_BSEX: u32 = 1 << 25;
const RCTL_SECRC: u32 = 1 << 26;
const RDBAL: u32 = 0x2800;
const RDBAH: u32 = 0x2804;
const RDLEN: u32 = 0x2808;
const RDH: u32 = 0x2810;
const RDT: u32 = 0x2818;
const RAL0: u32 = 0x5400;
const RAH0: u32 = 0x5404;
#[derive(Debug)]
#[repr(packed)]
struct Rd {
buffer: u64,
length: u16,
checksum: u16,
status: u8,
error: u8,
special: u16,
}
const RD_DD: u8 = 1;
const RD_EOP: u8 = 1 << 1;
const TCTL: u32 = 0x400;
const TCTL_EN: u32 = 1 << 1;
const TCTL_PSP: u32 = 1 << 3;
const TDBAL: u32 = 0x3800;
const TDBAH: u32 = 0x3804;
const TDLEN: u32 = 0x3808;
const TDH: u32 = 0x3810;
const TDT: u32 = 0x3818;
#[derive(Debug)]
#[repr(packed)]
struct Td {
buffer: u64,
length: u16,
cso: u8,
command: u8,
status: u8,
css: u8,
special: u16,
}
const TD_CMD_EOP: u8 = 1;
const TD_CMD_IFCS: u8 = 1 << 1;
const TD_CMD_RS: u8 = 1 << 3;
const TD_DD: u8 = 1;
pub struct Intel8254x {
base: usize,
receive_buffer: [Dma<[u8; 16384]>; 16],
receive_ring: Dma<[Rd; 16]>,
transmit_buffer: [Dma<[u8; 16384]>; 16],
transmit_ring: Dma<[Td; 16]>
}
impl Scheme for Intel8254x {
fn open(&self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid == 0 {
Ok(flags)
} else {
Err(Error::new(EACCES))
}
}
fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
Ok(id)
}
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
let head = unsafe { self.read(RDH) };
let mut tail = unsafe { self.read(RDT) };
tail += 1;
if tail >= self.receive_ring.len() as u32 {
tail = 0;
}
if tail != head {
let rd = unsafe { &mut * (self.receive_ring.as_ptr().offset(tail as isize) as *mut Rd) };
if rd.status & RD_DD == RD_DD {
rd.status = 0;
let data = &self.receive_buffer[tail as usize][.. rd.length as usize];
let mut i = 0;
while i < buf.len() && i < data.len() {
buf[i] = data[i];
i += 1;
}
unsafe { self.write(RDT, tail) };
return Ok(i);
}
}
if id & O_NONBLOCK == O_NONBLOCK {
Ok(0)
} else {
Err(Error::new(EWOULDBLOCK))
}
}
fn write(&self, _id: usize, buf: &[u8]) -> Result<usize> {
loop {
let head = unsafe { self.read(TDH) };
let mut tail = unsafe { self.read(TDT) };
let old_tail = tail;
tail += 1;
if tail >= self.transmit_ring.len() as u32 {
tail = 0;
}
if tail != head {
let td = unsafe { &mut * (self.transmit_ring.as_ptr().offset(old_tail as isize) as *mut Td) };
td.cso = 0;
td.command = TD_CMD_EOP | TD_CMD_IFCS | TD_CMD_RS;
td.status = 0;
td.css = 0;
td.special = 0;
td.length = (cmp::min(buf.len(), 0x3FFF)) as u16;
let mut data = unsafe { slice::from_raw_parts_mut(self.transmit_buffer[old_tail as usize].as_ptr() as *mut u8, td.length as usize) };
let mut i = 0;
while i < buf.len() && i < data.len() {
data[i] = buf[i];
i += 1;
}
unsafe { self.write(TDT, tail) };
while td.status == 0 {
unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); }
}
return Ok(i);
}
unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); }
}
}
fn fevent(&self, _id: usize, _flags: usize) -> Result<usize> {
Ok(0)
}
fn fsync(&self, _id: usize) -> Result<usize> {
Ok(0)
}
fn close(&self, _id: usize) -> Result<usize> {
Ok(0)
}
}
impl Intel8254x {
pub unsafe fn new(base: usize) -> Result<Self> {
let mut module = Intel8254x {
base: base,
receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?],
receive_ring: Dma::zeroed()?,
transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?],
transmit_ring: Dma::zeroed()?
};
module.init();
Ok(module)
}
pub unsafe fn irq(&self) -> bool {
let icr = self.read(ICR);
icr != 0
}
pub fn next_read(&self) -> usize {
let head = unsafe { self.read(RDH) };
let mut tail = unsafe { self.read(RDT) };
tail += 1;
if tail >= self.receive_ring.len() as u32 {
tail = 0;
}
if tail != head {
let rd = unsafe { &* (self.receive_ring.as_ptr().offset(tail as isize) as *const Rd) };
if rd.status & RD_DD == RD_DD {
return rd.length as usize;
}
}
0
}
pub unsafe fn read(&self, register: u32) -> u32 {
ptr::read_volatile((self.base + register as usize) as *mut u32)
}
pub unsafe fn write(&self, register: u32, data: u32) -> u32 {
ptr::write_volatile((self.base + register as usize) as *mut u32, data);
ptr::read_volatile((self.base + register as usize) as *mut u32)
}
pub unsafe fn flag(&self, register: u32, flag: u32, value: bool) {
if value {
self.write(register, self.read(register) | flag);
} else {
self.write(register, self.read(register) & (0xFFFFFFFF - flag));
}
}
pub unsafe fn init(&mut self) {
// Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal
self.flag(CTRL, CTRL_ASDE | CTRL_SLU, true);
self.flag(CTRL, CTRL_LRST, false);
self.flag(CTRL, CTRL_PHY_RST, false);
self.flag(CTRL, CTRL_ILOS, false);
// No flow control
self.write(FCAH, 0);
self.write(FCAL, 0);
self.write(FCT, 0);
self.write(FCTTV, 0);
// Do not use VLANs
self.flag(CTRL, CTRL_VME, false);
// TODO: Clear statistical counters
let mac_low = self.read(RAL0);
let mac_high = self.read(RAH0);
let mac = [mac_low as u8,
(mac_low >> 8) as u8,
(mac_low >> 16) as u8,
(mac_low >> 24) as u8,
mac_high as u8,
(mac_high >> 8) as u8];
print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
//
// MTA => 0;
//
// Receive Buffer
for i in 0..self.receive_ring.len() {
self.receive_ring[i].buffer = self.receive_buffer[i].physical() as u64;
}
self.write(RDBAH, (self.receive_ring.physical() >> 32) as u32);
self.write(RDBAL, self.receive_ring.physical() as u32);
self.write(RDLEN, (self.receive_ring.len() * mem::size_of::<Rd>()) as u32);
self.write(RDH, 0);
self.write(RDT, self.receive_ring.len() as u32 - 1);
// Transmit Buffer
for i in 0..self.transmit_ring.len() {
self.transmit_ring[i].buffer = self.transmit_buffer[i].physical() as u64;
}
self.write(TDBAH, (self.transmit_ring.physical() >> 32) as u32);
self.write(TDBAL, self.transmit_ring.physical() as u32);
self.write(TDLEN, (self.transmit_ring.len() * mem::size_of::<Td>()) as u32);
self.write(TDH, 0);
self.write(TDT, 0);
self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ); // | IMS_LSC | IMS_TXQE | IMS_TXDW
self.flag(RCTL, RCTL_EN, true);
self.flag(RCTL, RCTL_UPE, true);
// self.flag(RCTL, RCTL_MPE, true);
self.flag(RCTL, RCTL_LPE, true);
self.flag(RCTL, RCTL_LBM, false);
// RCTL.RDMTS = Minimum threshold size ???
// RCTL.MO = Multicast offset
self.flag(RCTL, RCTL_BAM, true);
self.flag(RCTL, RCTL_BSIZE1, true);
self.flag(RCTL, RCTL_BSIZE2, false);
self.flag(RCTL, RCTL_BSEX, true);
self.flag(RCTL, RCTL_SECRC, true);
self.flag(TCTL, TCTL_EN, true);
self.flag(TCTL, TCTL_PSP, true);
// TCTL.CT = Collision threshold
// TCTL.COLD = Collision distance
// TIPG Packet Gap
// TODO ...
}
}

View file

@ -1,136 +0,0 @@
#![feature(asm)]
extern crate dma;
extern crate event;
extern crate netutils;
extern crate syscall;
use std::cell::RefCell;
use std::env;
use std::fs::File;
use std::io::{Read, Write, Result};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use event::EventQueue;
use syscall::{Packet, Scheme, MAP_WRITE};
use syscall::error::EWOULDBLOCK;
pub mod device;
fn main() {
let mut args = env::args().skip(1);
let mut name = args.next().expect("e1000d: no name provided");
name.push_str("_e1000");
let bar_str = args.next().expect("e1000d: no address provided");
let bar = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address");
let irq_str = args.next().expect("e1000d: no irq provided");
let irq = irq_str.parse::<u8>().expect("e1000d: failed to parse irq");
print!("{}", format!(" + E1000 {} on: {:X}, IRQ: {}\n", name, bar, irq));
// Daemonize
if unsafe { syscall::clone(0).unwrap() } == 0 {
let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("e1000d: failed to create network scheme");
let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) }));
let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") };
{
let device = Arc::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") });
let mut event_queue = EventQueue::<usize>::new().expect("e1000d: failed to create event queue");
let todo = Arc::new(RefCell::new(Vec::<Packet>::new()));
let device_irq = device.clone();
let socket_irq = socket.clone();
let todo_irq = todo.clone();
let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file");
event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result<Option<usize>> {
let mut irq = [0; 8];
irq_file.read(&mut irq)?;
if unsafe { device_irq.irq() } {
irq_file.write(&mut irq)?;
let mut todo = todo_irq.borrow_mut();
let mut i = 0;
while i < todo.len() {
let a = todo[i].a;
device_irq.handle(&mut todo[i]);
if todo[i].a == (-EWOULDBLOCK) as usize {
todo[i].a = a;
i += 1;
} else {
socket_irq.borrow_mut().write(&mut todo[i])?;
todo.remove(i);
}
}
let next_read = device_irq.next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
}
Ok(None)
}).expect("e1000d: failed to catch events on IRQ file");
let socket_packet = socket.clone();
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<usize>> {
loop {
let mut packet = Packet::default();
if socket_packet.borrow_mut().read(&mut packet)? == 0 {
break;
}
let a = packet.a;
device.handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket_packet.borrow_mut().write(&mut packet)?;
}
}
let next_read = device.next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
Ok(None)
}).expect("e1000d: failed to catch events on IRQ file");
for event_count in event_queue.trigger_all(0).expect("e1000d: failed to trigger events") {
socket.borrow_mut().write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: 0,
c: syscall::flag::EVENT_READ,
d: event_count
}).expect("e1000d: failed to write event");
}
loop {
let event_count = event_queue.run().expect("e1000d: failed to handle events");
socket.borrow_mut().write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: 0,
c: syscall::flag::EVENT_READ,
d: event_count
}).expect("e1000d: failed to write event");
}
}
unsafe { let _ = syscall::physunmap(address); }
}
}

View file

@ -1,8 +0,0 @@
[package]
name = "pcid"
version = "0.1.0"
[dependencies]
redox_syscall = { path = "../../syscall/" }
rustc-serialize = "0.3"
toml = "0.2"

View file

@ -1,14 +0,0 @@
#[derive(Debug, Default, RustcDecodable)]
pub struct Config {
pub drivers: Vec<DriverConfig>
}
#[derive(Debug, Default, RustcDecodable)]
pub struct DriverConfig {
pub name: Option<String>,
pub class: Option<u8>,
pub subclass: Option<u8>,
pub vendor: Option<u16>,
pub device: Option<u16>,
pub command: Option<Vec<String>>
}

View file

@ -1,160 +0,0 @@
#![feature(asm)]
extern crate rustc_serialize;
extern crate syscall;
extern crate toml;
use std::env;
use std::fs::File;
use std::io::Read;
use std::process::Command;
use syscall::iopl;
use config::Config;
use pci::{Pci, PciBar, PciClass};
mod config;
mod pci;
fn main() {
let mut config = Config::default();
let mut args = env::args().skip(1);
if let Some(config_path) = args.next() {
if let Ok(mut config_file) = File::open(&config_path) {
let mut config_data = String::new();
if let Ok(_) = config_file.read_to_string(&mut config_data) {
config = toml::decode_str(&config_data).unwrap_or(Config::default());
}
}
}
unsafe { iopl(3).unwrap() };
print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n");
let pci = Pci::new();
for bus in pci.buses() {
for dev in bus.devs() {
for func in dev.funcs() {
if let Some(header) = func.header() {
let pci_class = PciClass::from(header.class);
let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}",
bus.num, dev.num, func.num,
header.vendor_id, header.device_id,
header.class, header.subclass, header.interface, header.revision,
pci_class);
match pci_class {
PciClass::Storage => match header.subclass {
0x01 => {
string.push_str(" IDE");
},
0x06 => {
string.push_str(" SATA");
},
_ => ()
},
PciClass::SerialBus => match header.subclass {
0x03 => match header.interface {
0x00 => {
string.push_str(" UHCI");
},
0x10 => {
string.push_str(" OHCI");
},
0x20 => {
string.push_str(" EHCI");
},
0x30 => {
string.push_str(" XHCI");
},
_ => ()
},
_ => ()
},
_ => ()
}
for i in 0..header.bars.len() {
match PciBar::from(header.bars[i]) {
PciBar::None => (),
PciBar::Memory(address) => string.push_str(&format!(" {}={:>08X}", i, address)),
PciBar::Port(address) => string.push_str(&format!(" {}={:>04X}", i, address))
}
}
string.push('\n');
print!("{}", string);
for driver in config.drivers.iter() {
if let Some(class) = driver.class {
if class != header.class { continue; }
}
if let Some(subclass) = driver.subclass {
if subclass != header.subclass { continue; }
}
if let Some(vendor) = driver.vendor {
if vendor != header.vendor_id { continue; }
}
if let Some(device) = driver.device {
if device != header.device_id { continue; }
}
if let Some(ref args) = driver.command {
// Enable bus mastering
unsafe {
let cmd = pci.read(bus.num, dev.num, func.num, 0x04);
pci.write(bus.num, dev.num, func.num, 0x04, cmd | 4);
}
let mut args = args.iter();
if let Some(program) = args.next() {
let mut command = Command::new(program);
for arg in args {
let bar_arg = |i| -> String {
match PciBar::from(header.bars[i]) {
PciBar::None => String::new(),
PciBar::Memory(address) => format!("{:>08X}", address),
PciBar::Port(address) => format!("{:>04X}", address)
}
};
let arg = match arg.as_str() {
"$BUS" => format!("{:>02X}", bus.num),
"$DEV" => format!("{:>02X}", dev.num),
"$FUNC" => format!("{:>02X}", func.num),
"$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus.num, dev.num, func.num),
"$BAR0" => bar_arg(0),
"$BAR1" => bar_arg(1),
"$BAR2" => bar_arg(2),
"$BAR3" => bar_arg(3),
"$BAR4" => bar_arg(4),
"$BAR5" => bar_arg(5),
"$IRQ" => format!("{}", header.interrupt_line),
_ => arg.clone()
};
command.arg(&arg);
}
println!("PCID SPAWN {:?}", command);
match command.spawn() {
Ok(mut child) => match child.wait() {
Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()),
Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err)
},
Err(err) => println!("pcid: failed to execute {:?}: {}", command, err)
}
}
}
}
}
}
}
}
}

View file

@ -1,18 +0,0 @@
#[derive(Debug)]
pub enum PciBar {
None,
Memory(u32),
Port(u16)
}
impl From<u32> for PciBar {
fn from(bar: u32) -> Self {
if bar & 0xFFFFFFFC == 0 {
PciBar::None
} else if bar & 1 == 0 {
PciBar::Memory(bar & 0xFFFFFFF0)
} else {
PciBar::Port((bar & 0xFFFC) as u16)
}
}
}

View file

@ -1,46 +0,0 @@
use super::{Pci, PciDev};
pub struct PciBus<'pci> {
pub pci: &'pci Pci,
pub num: u8
}
impl<'pci> PciBus<'pci> {
pub fn devs(&'pci self) -> PciBusIter<'pci> {
PciBusIter::new(self)
}
pub unsafe fn read(&self, dev: u8, func: u8, offset: u8) -> u32 {
self.pci.read(self.num, dev, func, offset)
}
}
pub struct PciBusIter<'pci> {
bus: &'pci PciBus<'pci>,
num: u32
}
impl<'pci> PciBusIter<'pci> {
pub fn new(bus: &'pci PciBus<'pci>) -> Self {
PciBusIter {
bus: bus,
num: 0
}
}
}
impl<'pci> Iterator for PciBusIter<'pci> {
type Item = PciDev<'pci>;
fn next(&mut self) -> Option<Self::Item> {
if self.num < 32 {
let dev = PciDev {
bus: self.bus,
num: self.num as u8
};
self.num += 1;
Some(dev)
} else {
None
}
}
}

View file

@ -1,50 +0,0 @@
#[derive(Debug)]
pub enum PciClass {
Legacy,
Storage,
Network,
Display,
Multimedia,
Memory,
Bridge,
SimpleComms,
Peripheral,
Input,
Docking,
Processor,
SerialBus,
Wireless,
IntelligentIo,
SatelliteComms,
Cryptography,
SignalProc,
Reserved(u8),
Unknown
}
impl From<u8> for PciClass {
fn from(class: u8) -> PciClass {
match class {
0x00 => PciClass::Legacy,
0x01 => PciClass::Storage,
0x02 => PciClass::Network,
0x03 => PciClass::Display,
0x04 => PciClass::Multimedia,
0x05 => PciClass::Memory,
0x06 => PciClass::Bridge,
0x07 => PciClass::SimpleComms,
0x08 => PciClass::Peripheral,
0x09 => PciClass::Input,
0x0A => PciClass::Docking,
0x0B => PciClass::Processor,
0x0C => PciClass::SerialBus,
0x0D => PciClass::Wireless,
0x0E => PciClass::IntelligentIo,
0x0F => PciClass::SatelliteComms,
0x10 => PciClass::Cryptography,
0x11 => PciClass::SignalProc,
0xFF => PciClass::Unknown,
reserved => PciClass::Reserved(reserved)
}
}
}

View file

@ -1,46 +0,0 @@
use super::{PciBus, PciFunc};
pub struct PciDev<'pci> {
pub bus: &'pci PciBus<'pci>,
pub num: u8
}
impl<'pci> PciDev<'pci> {
pub fn funcs(&'pci self) -> PciDevIter<'pci> {
PciDevIter::new(self)
}
pub unsafe fn read(&self, func: u8, offset: u8) -> u32 {
self.bus.read(self.num, func, offset)
}
}
pub struct PciDevIter<'pci> {
dev: &'pci PciDev<'pci>,
num: u32
}
impl<'pci> PciDevIter<'pci> {
pub fn new(dev: &'pci PciDev<'pci>) -> Self {
PciDevIter {
dev: dev,
num: 0
}
}
}
impl<'pci> Iterator for PciDevIter<'pci> {
type Item = PciFunc<'pci>;
fn next(&mut self) -> Option<Self::Item> {
if self.num < 8 {
let func = PciFunc {
dev: self.dev,
num: self.num as u8
};
self.num += 1;
Some(func)
} else {
None
}
}
}

View file

@ -1,30 +0,0 @@
use std::ops::DerefMut;
use super::{PciDev, PciHeader};
pub struct PciFunc<'pci> {
pub dev: &'pci PciDev<'pci>,
pub num: u8
}
impl<'pci> PciFunc<'pci> {
pub fn header(&self) -> Option<PciHeader> {
if unsafe { self.read(0) } != 0xFFFFFFFF {
let mut header = PciHeader::default();
{
let dwords = header.deref_mut();
dwords.iter_mut().fold(0usize, |offset, dword| {
*dword = unsafe { self.read(offset as u8) };
offset + 4
});
}
Some(header)
} else {
None
}
}
pub unsafe fn read(&self, offset: u8) -> u32 {
self.dev.read(self.num, offset)
}
}

View file

@ -1,43 +0,0 @@
use std::ops::{Deref, DerefMut};
use std::{slice, mem};
#[derive(Debug, Default)]
#[repr(packed)]
pub struct PciHeader {
pub vendor_id: u16,
pub device_id: u16,
pub command: u16,
pub status: u16,
pub revision: u8,
pub interface: u8,
pub subclass: u8,
pub class: u8,
pub cache_line_size: u8,
pub latency_timer: u8,
pub header_type: u8,
pub bist: u8,
pub bars: [u32; 6],
pub cardbus_cis_ptr: u32,
pub subsystem_vendor_id: u16,
pub subsystem_id: u16,
pub expansion_rom_bar: u32,
pub capabilities: u8,
pub reserved: [u8; 7],
pub interrupt_line: u8,
pub interrupt_pin: u8,
pub min_grant: u8,
pub max_latency: u8
}
impl Deref for PciHeader {
type Target = [u32];
fn deref(&self) -> &[u32] {
unsafe { slice::from_raw_parts(self as *const PciHeader as *const u32, mem::size_of::<PciHeader>()/4) as &[u32] }
}
}
impl DerefMut for PciHeader {
fn deref_mut(&mut self) -> &mut [u32] {
unsafe { slice::from_raw_parts_mut(self as *mut PciHeader as *mut u32, mem::size_of::<PciHeader>()/4) as &mut [u32] }
}
}

View file

@ -1,78 +0,0 @@
pub use self::bar::PciBar;
pub use self::bus::{PciBus, PciBusIter};
pub use self::class::PciClass;
pub use self::dev::{PciDev, PciDevIter};
pub use self::func::PciFunc;
pub use self::header::PciHeader;
mod bar;
mod bus;
mod class;
mod dev;
mod func;
mod header;
pub struct Pci;
impl Pci {
pub fn new() -> Self {
Pci
}
pub fn buses<'pci>(&'pci self) -> PciIter<'pci> {
PciIter::new(self)
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 {
let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC);
let value: u32;
asm!("mov dx, 0xCF8
out dx, eax
mov dx, 0xCFC
in eax, dx"
: "={eax}"(value) : "{eax}"(address) : "dx" : "intel", "volatile");
value
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) {
let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC);
asm!("mov dx, 0xCF8
out dx, eax"
: : "{eax}"(address) : "dx" : "intel", "volatile");
asm!("mov dx, 0xCFC
out dx, eax"
: : "{eax}"(value) : "dx" : "intel", "volatile");
}
}
pub struct PciIter<'pci> {
pci: &'pci Pci,
num: u32
}
impl<'pci> PciIter<'pci> {
pub fn new(pci: &'pci Pci) -> Self {
PciIter {
pci: pci,
num: 0
}
}
}
impl<'pci> Iterator for PciIter<'pci> {
type Item = PciBus<'pci>;
fn next(&mut self) -> Option<Self::Item> {
if self.num < 256 {
let bus = PciBus {
pci: self.pci,
num: self.num as u8
};
self.num += 1;
Some(bus)
} else {
None
}
}
}

View file

@ -1,10 +0,0 @@
[package]
name = "ps2d"
version = "0.1.0"
[dependencies]
bitflags = "*"
event = { path = "../../crates/event/" }
io = { path = "../../crates/io/" }
orbclient = "0.1"
redox_syscall = { path = "../../syscall/" }

View file

@ -1,233 +0,0 @@
use io::{Io, Pio, ReadOnly, WriteOnly};
bitflags! {
flags StatusFlags: u8 {
const OUTPUT_FULL = 1,
const INPUT_FULL = 1 << 1,
const SYSTEM = 1 << 2,
const COMMAND = 1 << 3,
// Chipset specific
const KEYBOARD_LOCK = 1 << 4,
// Chipset specific
const SECOND_OUTPUT_FULL = 1 << 5,
const TIME_OUT = 1 << 6,
const PARITY = 1 << 7
}
}
bitflags! {
flags ConfigFlags: u8 {
const FIRST_INTERRUPT = 1,
const SECOND_INTERRUPT = 1 << 1,
const POST_PASSED = 1 << 2,
// 1 << 3 should be zero
const CONFIG_RESERVED_3 = 1 << 3,
const FIRST_DISABLED = 1 << 4,
const SECOND_DISABLED = 1 << 5,
const FIRST_TRANSLATE = 1 << 6,
// 1 << 7 should be zero
const CONFIG_RESERVED_7 = 1 << 7,
}
}
#[repr(u8)]
#[allow(dead_code)]
enum Command {
ReadConfig = 0x20,
WriteConfig = 0x60,
DisableSecond = 0xA7,
EnableSecond = 0xA8,
TestSecond = 0xA9,
TestController = 0xAA,
TestFirst = 0xAB,
Diagnostic = 0xAC,
DisableFirst = 0xAD,
EnableFirst = 0xAE,
WriteSecond = 0xD4
}
#[repr(u8)]
#[allow(dead_code)]
enum KeyboardCommand {
EnableReporting = 0xF4,
SetDefaults = 0xF6,
Reset = 0xFF
}
#[repr(u8)]
enum KeyboardCommandData {
ScancodeSet = 0xF0
}
#[repr(u8)]
#[allow(dead_code)]
enum MouseCommand {
GetDeviceId = 0xF2,
EnableReporting = 0xF4,
SetDefaults = 0xF6,
Reset = 0xFF
}
#[repr(u8)]
enum MouseCommandData {
SetSampleRate = 0xF3,
}
pub struct Ps2 {
data: Pio<u8>,
status: ReadOnly<Pio<u8>>,
command: WriteOnly<Pio<u8>>
}
impl Ps2 {
pub fn new() -> Self {
Ps2 {
data: Pio::new(0x60),
status: ReadOnly::new(Pio::new(0x64)),
command: WriteOnly::new(Pio::new(0x64)),
}
}
fn status(&mut self) -> StatusFlags {
StatusFlags::from_bits_truncate(self.status.read())
}
fn wait_write(&mut self) {
while self.status().contains(INPUT_FULL) {}
}
fn wait_read(&mut self) {
while ! self.status().contains(OUTPUT_FULL) {}
}
fn flush_read(&mut self) {
while self.status().contains(OUTPUT_FULL) {
print!("FLUSH: {:X}\n", self.data.read());
}
}
fn command(&mut self, command: Command) {
self.wait_write();
self.command.write(command as u8);
}
fn read(&mut self) -> u8 {
self.wait_read();
self.data.read()
}
fn write(&mut self, data: u8) {
self.wait_write();
self.data.write(data);
}
fn config(&mut self) -> ConfigFlags {
self.command(Command::ReadConfig);
ConfigFlags::from_bits_truncate(self.read())
}
fn set_config(&mut self, config: ConfigFlags) {
self.command(Command::WriteConfig);
self.write(config.bits());
}
fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 {
self.write(command as u8);
self.read()
}
fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> u8 {
self.write(command as u8);
assert_eq!(self.read(), 0xFA);
self.write(data as u8);
self.read()
}
fn mouse_command(&mut self, command: MouseCommand) -> u8 {
self.command(Command::WriteSecond);
self.write(command as u8);
self.read()
}
fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> u8 {
self.command(Command::WriteSecond);
self.write(command as u8);
assert_eq!(self.read(), 0xFA);
self.command(Command::WriteSecond);
self.write(data as u8);
self.read()
}
pub fn init(&mut self) -> bool {
// Disable devices
self.command(Command::DisableFirst);
self.command(Command::DisableSecond);
// Clear remaining data
self.flush_read();
// Disable clocks, disable interrupts, and disable translate
{
let mut config = self.config();
config.insert(FIRST_DISABLED);
config.insert(SECOND_DISABLED);
config.remove(FIRST_TRANSLATE);
config.remove(FIRST_INTERRUPT);
config.remove(SECOND_INTERRUPT);
self.set_config(config);
}
// Perform the self test
self.command(Command::TestController);
assert_eq!(self.read(), 0x55);
// Enable devices
self.command(Command::EnableFirst);
self.command(Command::EnableSecond);
// Reset keyboard
assert_eq!(self.keyboard_command(KeyboardCommand::Reset), 0xFA);
assert_eq!(self.read(), 0xAA);
self.flush_read();
// Set scancode set to 2
assert_eq!(self.keyboard_command_data(KeyboardCommandData::ScancodeSet, 2), 0xFA);
// Reset mouse and set up scroll
// TODO: Check for ack
assert_eq!(self.mouse_command(MouseCommand::Reset), 0xFA);
assert_eq!(self.read(), 0xAA);
assert_eq!(self.read(), 0x00);
self.flush_read();
// Enable extra packet on mouse
assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA);
assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 100), 0xFA);
assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 80), 0xFA);
assert_eq!(self.mouse_command(MouseCommand::GetDeviceId), 0xFA);
let mouse_id = self.read();
let mouse_extra = mouse_id == 3;
// Set sample rate to maximum
assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA);
// Enable data reporting
assert_eq!(self.keyboard_command(KeyboardCommand::EnableReporting), 0xFA);
assert_eq!(self.mouse_command(MouseCommand::EnableReporting), 0xFA);
// Enable clocks and interrupts
{
let mut config = self.config();
config.remove(FIRST_DISABLED);
config.remove(SECOND_DISABLED);
config.insert(FIRST_TRANSLATE);
config.insert(FIRST_INTERRUPT);
config.insert(SECOND_INTERRUPT);
self.set_config(config);
}
self.flush_read();
mouse_extra
}
}

View file

@ -1,148 +0,0 @@
pub mod english {
static ENGLISH: [[char; 2]; 58] = [
['\0', '\0'],
['\x1B', '\x1B'],
['1', '!'],
['2', '@'],
['3', '#'],
['4', '$'],
['5', '%'],
['6', '^'],
['7', '&'],
['8', '*'],
['9', '('],
['0', ')'],
['-', '_'],
['=', '+'],
['\x7F', '\x7F'],
['\t', '\t'],
['q', 'Q'],
['w', 'W'],
['e', 'E'],
['r', 'R'],
['t', 'T'],
['y', 'Y'],
['u', 'U'],
['i', 'I'],
['o', 'O'],
['p', 'P'],
['[', '{'],
[']', '}'],
['\n', '\n'],
['\0', '\0'],
['a', 'A'],
['s', 'S'],
['d', 'D'],
['f', 'F'],
['g', 'G'],
['h', 'H'],
['j', 'J'],
['k', 'K'],
['l', 'L'],
[';', ':'],
['\'', '"'],
['`', '~'],
['\0', '\0'],
['\\', '|'],
['z', 'Z'],
['x', 'X'],
['c', 'C'],
['v', 'V'],
['b', 'B'],
['n', 'N'],
['m', 'M'],
[',', '<'],
['.', '>'],
['/', '?'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
];
pub fn get_char(scancode: u8, shift: bool) -> char {
if let Some(c) = ENGLISH.get(scancode as usize) {
if shift {
c[1]
} else {
c[0]
}
} else {
'\0'
}
}
}
pub mod dvorak {
static DVORAK: [[char; 2]; 58] = [
['\0', '\0'],
['\x1B', '\x1B'],
['1', '!'],
['2', '@'],
['3', '#'],
['4', '$'],
['5', '%'],
['6', '^'],
['7', '&'],
['8', '*'],
['9', '('],
['0', ')'],
['[', '{'],
[']', '}'],
['\x7F', '\x7F'],
['\t', '\t'],
['\'', '"'],
[',', '<'],
['.', '>'],
['p', 'P'],
['y', 'Y'],
['f', 'F'],
['g', 'G'],
['c', 'C'],
['r', 'R'],
['l', 'L'],
['/', '?'],
['=', '+'],
['\n', '\n'],
['\0', '\0'],
['a', 'A'],
['o', 'O'],
['e', 'E'],
['u', 'U'],
['i', 'I'],
['d', 'D'],
['h', 'H'],
['t', 'T'],
['n', 'N'],
['s', 'S'],
['-', '_'],
['`', '~'],
['\0', '\0'],
['\\', '|'],
[';', ':'],
['q', 'Q'],
['j', 'J'],
['k', 'K'],
['x', 'X'],
['b', 'B'],
['m', 'M'],
['w', 'W'],
['v', 'V'],
['z', 'Z'],
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
];
pub fn get_char(scancode: u8, shift: bool) -> char {
if let Some(c) = DVORAK.get(scancode as usize) {
if shift {
c[1]
} else {
c[0]
}
} else {
'\0'
}
}
}

View file

@ -1,193 +0,0 @@
#![feature(asm)]
#[macro_use]
extern crate bitflags;
extern crate event;
extern crate io;
extern crate orbclient;
extern crate syscall;
use std::env;
use std::fs::File;
use std::io::{Read, Write, Result};
use std::os::unix::io::AsRawFd;
use std::mem;
use event::EventQueue;
use orbclient::{KeyEvent, MouseEvent};
use syscall::iopl;
mod controller;
mod keymap;
bitflags! {
flags MousePacketFlags: u8 {
const LEFT_BUTTON = 1,
const RIGHT_BUTTON = 1 << 1,
const MIDDLE_BUTTON = 1 << 2,
const ALWAYS_ON = 1 << 3,
const X_SIGN = 1 << 4,
const Y_SIGN = 1 << 5,
const X_OVERFLOW = 1 << 6,
const Y_OVERFLOW = 1 << 7
}
}
struct Ps2d<'a> {
input: File,
lshift: bool,
rshift: bool,
packets: [u8; 4],
packet_i: usize,
extra_packet: bool,
//Keymap function
get_char: &'a Fn(u8,bool) -> char
}
impl<'a> Ps2d<'a> {
fn new(input: File, extra_packet: bool, keymap: &'a Fn(u8,bool) -> char) -> Self {
Ps2d {
input: input,
lshift: false,
rshift: false,
packets: [0; 4],
packet_i: 0,
extra_packet: extra_packet,
get_char: keymap
}
}
fn handle(&mut self, keyboard: bool, data: u8) {
if keyboard {
let (scancode, pressed) = if data >= 0x80 {
(data - 0x80, false)
} else {
(data, true)
};
if scancode == 0x2A {
self.lshift = pressed;
} else if scancode == 0x36 {
self.rshift = pressed;
}
self.input.write(&KeyEvent {
character: (self.get_char)(scancode, self.lshift || self.rshift),
scancode: scancode,
pressed: pressed
}.to_event()).expect("ps2d: failed to write key event");
} else {
self.packets[self.packet_i] = data;
self.packet_i += 1;
let flags = MousePacketFlags::from_bits_truncate(self.packets[0]);
if ! flags.contains(ALWAYS_ON) {
println!("MOUSE MISALIGN {:X}", self.packets[0]);
self.packets = [0; 4];
self.packet_i = 0;
} else if self.packet_i >= self.packets.len() || (!self.extra_packet && self.packet_i >= 3) {
if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) {
let mut dx = self.packets[1] as i32;
if flags.contains(X_SIGN) {
dx -= 0x100;
}
let mut dy = -(self.packets[2] as i32);
if flags.contains(Y_SIGN) {
dy += 0x100;
}
let _extra = if self.extra_packet {
self.packets[3]
} else {
0
};
self.input.write(&MouseEvent {
x: dx,
y: dy,
left_button: flags.contains(LEFT_BUTTON),
middle_button: flags.contains(MIDDLE_BUTTON),
right_button: flags.contains(RIGHT_BUTTON)
}.to_event()).expect("ps2d: failed to write mouse event");
} else {
println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]);
}
self.packets = [0; 4];
self.packet_i = 0;
}
}
}
}
fn main() {
// Daemonize
if unsafe { syscall::clone(0).unwrap() } == 0 {
unsafe {
iopl(3).expect("ps2d: failed to get I/O permission");
asm!("cli" : : : : "intel", "volatile");
}
let input = File::open("display:input").expect("ps2d: failed to open display:input");
let extra_packet = controller::Ps2::new().init();
let keymap = match env::args().skip(1).next() {
Some(k) => match k.to_lowercase().as_ref() {
"dvorak" => (keymap::dvorak::get_char),
"english" => (keymap::english::get_char),
&_ => (keymap::english::get_char)
},
None => (keymap::english::get_char)
};
let mut ps2d = Ps2d::new(input, extra_packet,&keymap);
let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue");
let mut key_irq = File::open("irq:1").expect("ps2d: failed to open irq:1");
event_queue.add(key_irq.as_raw_fd(), move |_count: usize| -> Result<Option<(bool, u8)>> {
let mut irq = [0; 8];
if key_irq.read(&mut irq)? >= mem::size_of::<usize>() {
let data: u8;
unsafe {
asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile");
}
key_irq.write(&irq)?;
Ok(Some((true, data)))
} else {
Ok(None)
}
}).expect("ps2d: failed to poll irq:1");
let mut mouse_irq = File::open("irq:12").expect("ps2d: failed to open irq:12");
event_queue.add(mouse_irq.as_raw_fd(), move |_count: usize| -> Result<Option<(bool, u8)>> {
let mut irq = [0; 8];
if mouse_irq.read(&mut irq)? >= mem::size_of::<usize>() {
let data: u8;
unsafe {
asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile");
}
mouse_irq.write(&irq)?;
Ok(Some((false, data)))
} else {
Ok(None)
}
}).expect("ps2d: failed to poll irq:12");
for (keyboard, data) in event_queue.trigger_all(0).expect("ps2d: failed to trigger events") {
ps2d.handle(keyboard, data);
}
loop {
let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events");
ps2d.handle(keyboard, data);
}
}
}

View file

@ -1,11 +0,0 @@
[package]
name = "rtl8168d"
version = "0.1.0"
[dependencies]
bitflags = "*"
dma = { path = "../../crates/dma/" }
event = { path = "../../crates/event/" }
io = { path = "../../crates/io/" }
netutils = { path = "../../programs/netutils/" }
redox_syscall = { path = "../../syscall/" }

View file

@ -1,300 +0,0 @@
use std::mem;
use dma::Dma;
use io::{Mmio, Io, ReadOnly};
use netutils::setcfg;
use syscall::error::{Error, EACCES, EWOULDBLOCK, Result};
use syscall::flag::O_NONBLOCK;
use syscall::scheme::SchemeMut;
#[repr(packed)]
struct Regs {
mac: [Mmio<u32>; 2],
_mar: [Mmio<u32>; 2],
_dtccr: [Mmio<u32>; 2],
_rsv0: [Mmio<u32>; 2],
tnpds: [Mmio<u32>; 2],
thpds: [Mmio<u32>; 2],
_rsv1: [Mmio<u8>; 7],
cmd: Mmio<u8>,
tppoll: Mmio<u8>,
_rsv2: [Mmio<u8>; 3],
imr: Mmio<u16>,
isr: Mmio<u16>,
tcr: Mmio<u32>,
rcr: Mmio<u32>,
_tctr: Mmio<u32>,
_rsv3: Mmio<u32>,
cmd_9346: Mmio<u8>,
_config: [Mmio<u8>; 6],
_rsv4: Mmio<u8>,
timer_int: Mmio<u32>,
_rsv5: Mmio<u32>,
_phys_ar: Mmio<u32>,
_rsv6: [Mmio<u32>; 2],
phys_sts: ReadOnly<Mmio<u8>>,
_rsv7: [Mmio<u8>; 23],
_wakeup: [Mmio<u32>; 16],
_crc: [Mmio<u16>; 5],
_rsv8: [Mmio<u8>; 12],
rms: Mmio<u16>,
_rsv9: Mmio<u32>,
_c_plus_cr: Mmio<u16>,
_rsv10: Mmio<u16>,
rdsar: [Mmio<u32>; 2],
mtps: Mmio<u8>,
_rsv11: [Mmio<u8>; 19],
}
const OWN: u32 = 1 << 31;
const EOR: u32 = 1 << 30;
const FS: u32 = 1 << 29;
const LS: u32 = 1 << 28;
#[repr(packed)]
struct Rd {
ctrl: Mmio<u32>,
_vlan: Mmio<u32>,
buffer: Mmio<u64>
}
#[repr(packed)]
struct Td {
ctrl: Mmio<u32>,
_vlan: Mmio<u32>,
buffer: Mmio<u64>
}
pub struct Rtl8168 {
regs: &'static mut Regs,
receive_buffer: [Dma<[Mmio<u8>; 0x1FF8]>; 16],
receive_ring: Dma<[Rd; 16]>,
transmit_buffer: [Dma<[Mmio<u8>; 7552]>; 16],
transmit_ring: Dma<[Td; 16]>,
transmit_buffer_h: [Dma<[Mmio<u8>; 7552]>; 1],
transmit_ring_h: Dma<[Td; 1]>
}
impl SchemeMut for Rtl8168 {
fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if uid == 0 {
Ok(flags)
} else {
Err(Error::new(EACCES))
}
}
fn dup(&mut self, id: usize, _buf: &[u8]) -> Result<usize> {
Ok(id)
}
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() {
if ! rd.ctrl.readf(OWN) {
let rd_len = rd.ctrl.read() & 0x3FFF;
let data = &self.receive_buffer[rd_i as usize];
let mut i = 0;
while i < buf.len() && i < rd_len as usize {
buf[i] = data[i].read();
i += 1;
}
let eor = rd.ctrl.read() & EOR;
rd.ctrl.write(OWN | eor | data.len() as u32);
return Ok(i);
}
}
if id & O_NONBLOCK == O_NONBLOCK {
Ok(0)
} else {
Err(Error::new(EWOULDBLOCK))
}
}
fn write(&mut self, _id: usize, buf: &[u8]) -> Result<usize> {
loop {
for (td_i, td) in self.transmit_ring.iter_mut().enumerate() {
if ! td.ctrl.readf(OWN) {
let mut data = &mut self.transmit_buffer[td_i as usize];
let mut i = 0;
while i < buf.len() && i < data.len() {
data[i].write(buf[i]);
i += 1;
}
let eor = td.ctrl.read() & EOR;
td.ctrl.write(OWN | eor | FS | LS | i as u32);
self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet
while self.regs.tppoll.readf(1 << 6) {
unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); }
}
return Ok(i);
}
}
unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); }
}
}
fn fevent(&mut self, _id: usize, _flags: usize) -> Result<usize> {
Ok(0)
}
fn fsync(&mut self, _id: usize) -> Result<usize> {
Ok(0)
}
fn close(&mut self, _id: usize) -> Result<usize> {
Ok(0)
}
}
impl Rtl8168 {
pub unsafe fn new(base: usize) -> Result<Self> {
assert_eq!(mem::size_of::<Regs>(), 256);
let regs = &mut *(base as *mut Regs);
assert_eq!(&regs.tnpds as *const _ as usize - base, 0x20);
assert_eq!(&regs.cmd as *const _ as usize - base, 0x37);
assert_eq!(&regs.tcr as *const _ as usize - base, 0x40);
assert_eq!(&regs.rcr as *const _ as usize - base, 0x44);
assert_eq!(&regs.cmd_9346 as *const _ as usize - base, 0x50);
assert_eq!(&regs.phys_sts as *const _ as usize - base, 0x6C);
assert_eq!(&regs.rms as *const _ as usize - base, 0xDA);
assert_eq!(&regs.rdsar as *const _ as usize - base, 0xE4);
assert_eq!(&regs.mtps as *const _ as usize - base, 0xEC);
let mut module = Rtl8168 {
regs: regs,
receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?],
receive_ring: Dma::zeroed()?,
transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?,
Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?],
transmit_ring: Dma::zeroed()?,
transmit_buffer_h: [Dma::zeroed()?],
transmit_ring_h: Dma::zeroed()?
};
module.init();
Ok(module)
}
pub unsafe fn irq(&mut self) -> u16 {
// Read and then clear the ISR
let isr = self.regs.isr.read();
self.regs.isr.write(isr);
let imr = self.regs.imr.read();
isr & imr
}
pub fn next_read(&self) -> usize {
for rd in self.receive_ring.iter() {
if ! rd.ctrl.readf(OWN) {
return rd.ctrl.read() as usize & 0x3FFF;
}
}
0
}
pub unsafe fn init(&mut self) {
let mac_low = self.regs.mac[0].read();
let mac_high = self.regs.mac[1].read();
let mac = [mac_low as u8,
(mac_low >> 8) as u8,
(mac_low >> 16) as u8,
(mac_low >> 24) as u8,
mac_high as u8,
(mac_high >> 8) as u8];
print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
// Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value
self.regs.cmd.writef(1 << 4, true);
while self.regs.cmd.readf(1 << 4) {}
// Set up rx buffers
for i in 0..self.receive_ring.len() {
let rd = &mut self.receive_ring[i];
let data = &mut self.receive_buffer[i];
rd.buffer.write(data.physical() as u64);
rd.ctrl.write(OWN | data.len() as u32);
}
if let Some(mut rd) = self.receive_ring.last_mut() {
rd.ctrl.writef(EOR, true);
}
// Set up normal priority tx buffers
for i in 0..self.transmit_ring.len() {
self.transmit_ring[i].buffer.write(self.transmit_buffer[i].physical() as u64);
}
if let Some(mut td) = self.transmit_ring.last_mut() {
td.ctrl.writef(EOR, true);
}
// Set up high priority tx buffers
for i in 0..self.transmit_ring_h.len() {
self.transmit_ring_h[i].buffer.write(self.transmit_buffer_h[i].physical() as u64);
}
if let Some(mut td) = self.transmit_ring_h.last_mut() {
td.ctrl.writef(EOR, true);
}
// Unlock config
self.regs.cmd_9346.write(1 << 7 | 1 << 6);
// Enable rx (bit 3) and tx (bit 2)
self.regs.cmd.writef(1 << 3 | 1 << 2, true);
// Max RX packet size
self.regs.rms.write(0x1FF8);
// Max TX packet size
self.regs.mtps.write(0x3B);
// Set tx low priority buffer address
self.regs.tnpds[0].write(self.transmit_ring.physical() as u32);
self.regs.tnpds[1].write((self.transmit_ring.physical() >> 32) as u32);
// Set tx high priority buffer address
self.regs.thpds[0].write(self.transmit_ring_h.physical() as u32);
self.regs.thpds[1].write((self.transmit_ring_h.physical() >> 32) as u32);
// Set rx buffer address
self.regs.rdsar[0].write(self.receive_ring.physical() as u32);
self.regs.rdsar[1].write((self.receive_ring.physical() >> 32) as u32);
// Disable timer interrupt
self.regs.timer_int.write(0);
//Clear ISR
let isr = self.regs.isr.read();
self.regs.isr.write(isr);
// Interrupt on tx error (bit 3), tx ok (bit 2), rx error(bit 1), and rx ok (bit 0)
self.regs.imr.write(1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1);
// Set TX config
self.regs.tcr.write(0b11 << 24 | 0b111 << 8);
// Set RX config - Accept broadcast (bit 3), multicast (bit 2), and unicast (bit 1)
self.regs.rcr.write(0xE70E);
// Lock config
self.regs.cmd_9346.write(0);
}
}

View file

@ -1,141 +0,0 @@
#![feature(asm)]
extern crate dma;
extern crate event;
extern crate io;
extern crate netutils;
extern crate syscall;
use std::cell::RefCell;
use std::env;
use std::fs::File;
use std::io::{Read, Write, Result};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use event::EventQueue;
use syscall::{Packet, SchemeMut, MAP_WRITE};
use syscall::error::EWOULDBLOCK;
pub mod device;
fn main() {
let mut args = env::args().skip(1);
let mut name = args.next().expect("rtl8168d: no name provided");
name.push_str("_rtl8168");
let bar_str = args.next().expect("rtl8168d: no address provided");
let bar = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address");
let irq_str = args.next().expect("rtl8168d: no irq provided");
let irq = irq_str.parse::<u8>().expect("rtl8168d: failed to parse irq");
print!("{}", format!(" + RTL8168 {} on: {:X}, IRQ: {}\n", name, bar, irq));
// Daemonize
if unsafe { syscall::clone(0).unwrap() } == 0 {
let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("rtl8168d: failed to create network scheme");
let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) }));
let mut irq_file = File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open IRQ file");
let address = unsafe { syscall::physmap(bar, 256, MAP_WRITE).expect("rtl8168d: failed to map address") };
{
let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") }));
let mut event_queue = EventQueue::<usize>::new().expect("rtl8168d: failed to create event queue");
let todo = Arc::new(RefCell::new(Vec::<Packet>::new()));
let device_irq = device.clone();
let socket_irq = socket.clone();
let todo_irq = todo.clone();
event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result<Option<usize>> {
let mut irq = [0; 8];
irq_file.read(&mut irq)?;
let isr = unsafe { device_irq.borrow_mut().irq() };
if isr != 0 {
irq_file.write(&mut irq)?;
let mut todo = todo_irq.borrow_mut();
let mut i = 0;
while i < todo.len() {
let a = todo[i].a;
device_irq.borrow_mut().handle(&mut todo[i]);
if todo[i].a == (-EWOULDBLOCK) as usize {
todo[i].a = a;
i += 1;
} else {
socket_irq.borrow_mut().write(&mut todo[i])?;
todo.remove(i);
}
}
let next_read = device_irq.borrow().next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
}
Ok(None)
}).expect("rtl8168d: failed to catch events on IRQ file");
let socket_fd = socket.borrow().as_raw_fd();
let socket_packet = socket.clone();
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<usize>> {
loop {
let mut packet = Packet::default();
if socket_packet.borrow_mut().read(&mut packet)? == 0 {
break;
}
let a = packet.a;
device.borrow_mut().handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
packet.a = a;
todo.borrow_mut().push(packet);
} else {
socket_packet.borrow_mut().write(&mut packet)?;
}
}
let next_read = device.borrow().next_read();
if next_read > 0 {
return Ok(Some(next_read));
}
Ok(None)
}).expect("rtl8168d: failed to catch events on IRQ file");
for event_count in event_queue.trigger_all(0).expect("rtl8168d: failed to trigger events") {
socket.borrow_mut().write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: 0,
c: syscall::flag::EVENT_READ,
d: event_count
}).expect("rtl8168d: failed to write event");
}
loop {
let event_count = event_queue.run().expect("rtl8168d: failed to handle events");
socket.borrow_mut().write(&Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: 0,
c: syscall::flag::EVENT_READ,
d: event_count
}).expect("rtl8168d: failed to write event");
}
}
unsafe { let _ = syscall::physunmap(address); }
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "vesad"
version = "0.1.0"
[dependencies]
orbclient = "0.1"
ransid = "0.2"
rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true }
redox_syscall = { path = "../../syscall" }
[features]
default = []

View file

@ -1,246 +0,0 @@
#[cfg(feature="rusttype")]
extern crate rusttype;
use alloc::heap;
use std::{cmp, slice};
use primitive::{fast_set32, fast_set64, fast_copy, fast_copy64};
#[cfg(feature="rusttype")]
use self::rusttype::{Font, FontCollection, Scale, point};
#[cfg(not(feature="rusttype"))]
static FONT: &'static [u8] = include_bytes!("../../../res/fonts/unifont.font");
#[cfg(feature="rusttype")]
static FONT: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono.ttf");
#[cfg(feature="rusttype")]
static FONT_BOLD: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf");
#[cfg(feature="rusttype")]
static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf");
#[cfg(feature="rusttype")]
static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf");
/// A display
pub struct Display {
pub width: usize,
pub height: usize,
pub onscreen: &'static mut [u32],
pub offscreen: &'static mut [u32],
#[cfg(feature="rusttype")]
pub font: Font<'static>,
#[cfg(feature="rusttype")]
pub font_bold: Font<'static>,
#[cfg(feature="rusttype")]
pub font_bold_italic: Font<'static>,
#[cfg(feature="rusttype")]
pub font_italic: Font<'static>
}
impl Display {
#[cfg(not(feature="rusttype"))]
pub fn new(width: usize, height: usize, onscreen: usize) -> Display {
let size = width * height;
let offscreen = unsafe { heap::allocate(size * 4, 4096) };
unsafe { fast_set64(offscreen as *mut u64, 0, size/2) };
Display {
width: width,
height: height,
onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) },
offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }
}
}
#[cfg(feature="rusttype")]
pub fn new(width: usize, height: usize, onscreen: usize) -> Display {
let size = width * height;
let offscreen = unsafe { heap::allocate(size * 4, 4096) };
unsafe { fast_set64(offscreen as *mut u64, 0, size/2) };
Display {
width: width,
height: height,
onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) },
offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) },
font: FontCollection::from_bytes(FONT).into_font().unwrap(),
font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(),
font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(),
font_italic: FontCollection::from_bytes(FONT_ITALIC).into_font().unwrap()
}
}
/// Draw a rectangle
pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
let start_y = cmp::min(self.height - 1, y);
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width - 1, x);
let len = cmp::min(self.width, x + w) - start_x;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let stride = self.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
unsafe {
fast_set32(offscreen_ptr as *mut u32, color, len);
}
offscreen_ptr += stride;
rows -= 1;
}
}
/// Invert a rectangle
pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) {
let start_y = cmp::min(self.height - 1, y);
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width - 1, x);
let len = cmp::min(self.width, x + w) - start_x;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let stride = self.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
let mut row_ptr = offscreen_ptr;
let mut cols = len;
while cols > 0 {
unsafe {
let color = *(row_ptr as *mut u32);
*(row_ptr as *mut u32) = !color;
}
row_ptr += 4;
cols -= 1;
}
offscreen_ptr += stride;
rows -= 1;
}
}
/// Draw a character
#[cfg(not(feature="rusttype"))]
pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) {
if x + 8 <= self.width && y + 16 <= self.height {
let mut dst = self.offscreen.as_mut_ptr() as usize + (y * self.width + x) * 4;
let font_i = 16 * (character as usize);
if font_i + 16 <= FONT.len() {
for row in 0..16 {
let row_data = FONT[font_i + row];
for col in 0..8 {
if (row_data >> (7 - col)) & 1 == 1 {
unsafe { *((dst + col * 4) as *mut u32) = color; }
}
}
dst += self.width * 4;
}
}
}
}
/// Draw a character
#[cfg(feature="rusttype")]
pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, bold: bool, italic: bool) {
let width = self.width;
let height = self.height;
let offscreen = self.offscreen.as_mut_ptr() as usize;
let font = if bold && italic {
&self.font_bold_italic
} else if bold {
&self.font_bold
} else if italic {
&self.font_italic
} else {
&self.font
};
if let Some(glyph) = font.glyph(character){
let scale = Scale::uniform(16.0);
let v_metrics = font.v_metrics(scale);
let point = point(0.0, v_metrics.ascent);
let glyph = glyph.scaled(scale).positioned(point);
if let Some(bb) = glyph.pixel_bounding_box() {
glyph.draw(|off_x, off_y, v| {
let off_x = x + (off_x as i32 + bb.min.x) as usize;
let off_y = y + (off_y as i32 + bb.min.y) as usize;
// There's still a possibility that the glyph clips the boundaries of the bitmap
if off_x < width && off_y < height {
if v > 0.0 {
let f_a = (v * 255.0) as u32;
let f_r = (((color >> 16) & 0xFF) * f_a)/255;
let f_g = (((color >> 8) & 0xFF) * f_a)/255;
let f_b = ((color & 0xFF) * f_a)/255;
let offscreen_ptr = (offscreen + (off_y * width + off_x) * 4) as *mut u32;
let bg = unsafe { *offscreen_ptr };
let b_a = 255 - f_a;
let b_r = (((bg >> 16) & 0xFF) * b_a)/255;
let b_g = (((bg >> 8) & 0xFF) * b_a)/255;
let b_b = ((bg & 0xFF) * b_a)/255;
let c = ((f_r + b_r) << 16) | ((f_g + b_g) << 8) | (f_b + b_b);
unsafe { *offscreen_ptr = c; }
}
}
});
}
}
}
/// Scroll display
pub fn scroll(&mut self, rows: usize, color: u32) {
let data = (color as u64) << 32 | color as u64;
let width = self.width/2;
let height = self.height;
if rows > 0 && rows < height {
let off1 = rows * width;
let off2 = height * width - off1;
unsafe {
let data_ptr = self.offscreen.as_mut_ptr() as *mut u64;
fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2);
fast_set64(data_ptr.offset(off2 as isize), data, off1);
}
}
}
/// Copy from offscreen to onscreen
pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize) {
let start_y = cmp::min(self.height - 1, y);
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width - 1, x);
let len = (cmp::min(self.width, x + w) - start_x) * 4;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize;
let stride = self.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
onscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
unsafe {
fast_copy(onscreen_ptr as *mut u8, offscreen_ptr as *const u8, len);
}
offscreen_ptr += stride;
onscreen_ptr += stride;
rows -= 1;
}
}
}

View file

@ -1,109 +0,0 @@
#![feature(alloc)]
#![feature(asm)]
#![feature(heap_api)]
extern crate alloc;
extern crate orbclient;
extern crate syscall;
use std::{env, mem};
use std::fs::File;
use std::io::{Read, Write};
use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE};
use mode_info::VBEModeInfo;
use primitive::fast_set64;
use scheme::DisplayScheme;
pub mod display;
pub mod mode_info;
pub mod primitive;
pub mod scheme;
pub mod screen;
fn main() {
let mut spec = Vec::new();
for arg in env::args().skip(1) {
if arg == "T" {
spec.push(false);
} else if arg == "G" {
spec.push(true);
} else {
println!("vesad: unknown screen type: {}", arg);
}
}
let width;
let height;
let physbaseptr;
{
let mode_info = unsafe { &*(physmap(0x5200, 4096, 0).expect("vesad: failed to map VBE info") as *const VBEModeInfo) };
width = mode_info.xresolution as usize;
height = mode_info.yresolution as usize;
physbaseptr = mode_info.physbaseptr as usize;
unsafe { let _ = physunmap(mode_info as *const _ as usize); }
}
if physbaseptr > 0 {
// Daemonize
if unsafe { syscall::clone(0).unwrap() } == 0 {
let mut socket = File::create(":display").expect("vesad: failed to create display scheme");
let size = width * height;
let onscreen = unsafe { physmap(physbaseptr, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") };
unsafe { fast_set64(onscreen as *mut u64, 0, size/2) };
let mut scheme = DisplayScheme::new(width, height, onscreen, &spec);
let mut blocked = Vec::new();
loop {
let mut packet = Packet::default();
socket.read(&mut packet).expect("vesad: failed to read display scheme");
// If it is a read packet, and there is no data, block it. Otherwise, handle packet
if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.will_block(packet.b) {
blocked.push(packet);
} else {
scheme.handle(&mut packet);
socket.write(&packet).expect("vesad: failed to write display scheme");
}
// If there are blocked readers, and data is available, handle them
{
let mut i = 0;
while i < blocked.len() {
if ! scheme.will_block(blocked[i].b) {
let mut packet = blocked.remove(i);
scheme.handle(&mut packet);
socket.write(&packet).expect("vesad: failed to write display scheme");
} else {
i += 1;
}
}
}
for (screen_id, screen) in scheme.screens.iter() {
if ! screen.will_block() {
let event_packet = Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: *screen_id,
c: EVENT_READ,
d: mem::size_of::<orbclient::Event>()
};
socket.write(&event_packet).expect("vesad: failed to write display event");
}
}
}
}
}
}

View file

@ -1,37 +0,0 @@
/// The info of the VBE mode
#[derive(Copy, Clone, Default, Debug)]
#[repr(packed)]
pub struct VBEModeInfo {
attributes: u16,
win_a: u8,
win_b: u8,
granularity: u16,
winsize: u16,
segment_a: u16,
segment_b: u16,
winfuncptr: u32,
bytesperscanline: u16,
pub xresolution: u16,
pub yresolution: u16,
xcharsize: u8,
ycharsize: u8,
numberofplanes: u8,
bitsperpixel: u8,
numberofbanks: u8,
memorymodel: u8,
banksize: u8,
numberofimagepages: u8,
unused: u8,
redmasksize: u8,
redfieldposition: u8,
greenmasksize: u8,
greenfieldposition: u8,
bluemasksize: u8,
bluefieldposition: u8,
rsvdmasksize: u8,
rsvdfieldposition: u8,
directcolormodeinfo: u8,
pub physbaseptr: u32,
offscreenmemoryoffset: u32,
offscreenmemsize: u16,
}

View file

@ -1,47 +0,0 @@
#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) {
asm!("cld
rep movsb"
:
: "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
: "cc", "memory", "rdi", "rsi", "rcx"
: "intel", "volatile");
}
#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
asm!("cld
rep movsq"
:
: "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
: "cc", "memory", "rdi", "rsi", "rcx"
: "intel", "volatile");
}
#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) {
asm!("cld
rep stosd"
:
: "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len)
: "cc", "memory", "rdi", "rcx"
: "intel", "volatile");
}
#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
asm!("cld
rep stosq"
:
: "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
: "cc", "memory", "rdi", "rcx"
: "intel", "volatile");
}

View file

@ -1,190 +0,0 @@
use std::collections::BTreeMap;
use std::{mem, slice, str};
use orbclient::{Event, EventOption};
use syscall::{Result, Error, EACCES, EBADF, ENOENT, SchemeMut};
use display::Display;
use screen::{Screen, GraphicScreen, TextScreen};
pub struct DisplayScheme {
active: usize,
pub screens: BTreeMap<usize, Box<Screen>>
}
impl DisplayScheme {
pub fn new(width: usize, height: usize, onscreen: usize, spec: &[bool]) -> DisplayScheme {
let mut screens: BTreeMap<usize, Box<Screen>> = BTreeMap::new();
let mut screen_i = 1;
for &screen_type in spec.iter() {
if screen_type {
screens.insert(screen_i, Box::new(GraphicScreen::new(Display::new(width, height, onscreen))));
} else {
screens.insert(screen_i, Box::new(TextScreen::new(Display::new(width, height, onscreen))));
}
screen_i += 1;
}
DisplayScheme {
active: 1,
screens: screens
}
}
pub fn will_block(&self, id: usize) -> bool {
if let Some(screen) = self.screens.get(&id) {
screen.will_block()
} else {
false
}
}
}
impl SchemeMut for DisplayScheme {
fn open(&mut self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
if path == b"input" {
if uid == 0 {
Ok(0)
} else {
Err(Error::new(EACCES))
}
} else {
let path_str = str::from_utf8(path).unwrap_or("").trim_matches('/');
let mut parts = path_str.split('/');
let id = parts.next().unwrap_or("").parse::<usize>().unwrap_or(0);
if self.screens.contains_key(&id) {
for cmd in parts {
if cmd == "activate" {
self.active = id;
}
}
Ok(id)
} else {
Err(Error::new(ENOENT))
}
}
}
fn dup(&mut self, id: usize, _buf: &[u8]) -> Result<usize> {
Ok(id)
}
fn fevent(&mut self, id: usize, flags: usize) -> Result<usize> {
if let Some(mut screen) = self.screens.get_mut(&id) {
screen.event(flags).and(Ok(id))
} else {
Err(Error::new(EBADF))
}
}
fn fmap(&mut self, id: usize, offset: usize, size: usize) -> Result<usize> {
if let Some(screen) = self.screens.get(&id) {
screen.map(offset, size)
} else {
Err(Error::new(EBADF))
}
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let path_str = if id == 0 {
format!("display:input")
} else if let Some(screen) = self.screens.get(&id) {
format!("display:{}/{}/{}", id, screen.width(), screen.height())
} else {
return Err(Error::new(EBADF));
};
let path = path_str.as_bytes();
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(i)
}
fn fsync(&mut self, id: usize) -> Result<usize> {
if let Some(mut screen) = self.screens.get_mut(&id) {
if id == self.active {
screen.sync();
}
Ok(0)
} else {
Err(Error::new(EBADF))
}
}
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
if let Some(mut screen) = self.screens.get_mut(&id) {
screen.read(buf)
} else {
Err(Error::new(EBADF))
}
}
fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
if id == 0 {
if buf.len() == 1 && buf[0] >= 0xF4 {
let new_active = (buf[0] - 0xF4) as usize + 1;
if let Some(mut screen) = self.screens.get_mut(&new_active) {
self.active = new_active;
screen.redraw();
}
Ok(1)
} else {
let events = unsafe { slice::from_raw_parts(buf.as_ptr() as *const Event, buf.len()/mem::size_of::<Event>()) };
for event in events.iter() {
let new_active_opt = if let EventOption::Key(key_event) = event.to_option() {
match key_event.scancode {
f @ 0x3B ... 0x44 => { // F1 through F10
Some((f - 0x3A) as usize)
},
0x57 => { // F11
Some(11)
},
0x58 => { // F12
Some(12)
},
_ => None
}
} else {
None
};
if let Some(new_active) = new_active_opt {
if let Some(mut screen) = self.screens.get_mut(&new_active) {
self.active = new_active;
screen.redraw();
}
} else {
if let Some(mut screen) = self.screens.get_mut(&self.active) {
screen.input(event);
}
}
}
Ok(events.len() * mem::size_of::<Event>())
}
} else if let Some(mut screen) = self.screens.get_mut(&id) {
screen.write(buf, id == self.active)
} else {
Err(Error::new(EBADF))
}
}
fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result<usize> {
if let Some(mut screen) = self.screens.get_mut(&id) {
screen.seek(pos, whence)
} else {
Err(Error::new(EBADF))
}
}
fn close(&mut self, _id: usize) -> Result<usize> {
Ok(0)
}
}

View file

@ -1,126 +0,0 @@
use std::collections::VecDeque;
use std::{cmp, mem, slice};
use orbclient::{Event, EventOption};
use syscall::error::*;
use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END};
use display::Display;
use primitive::fast_copy;
use screen::Screen;
pub struct GraphicScreen {
pub display: Display,
pub seek: usize,
pub mouse_x: i32,
pub mouse_y: i32,
pub input: VecDeque<Event>,
pub requested: usize
}
impl GraphicScreen {
pub fn new(display: Display) -> GraphicScreen {
GraphicScreen {
display: display,
seek: 0,
mouse_x: 0,
mouse_y: 0,
input: VecDeque::new(),
requested: 0
}
}
}
impl Screen for GraphicScreen {
fn width(&self) -> usize {
self.display.width
}
fn height(&self) -> usize {
self.display.height
}
fn event(&mut self, flags: usize) -> Result<usize> {
self.requested = flags;
Ok(0)
}
fn map(&self, offset: usize, size: usize) -> Result<usize> {
if offset + size <= self.display.offscreen.len() * 4 {
Ok(self.display.offscreen.as_ptr() as usize + offset)
} else {
Err(Error::new(EINVAL))
}
}
fn input(&mut self, event: &Event) {
if let EventOption::Mouse(mut mouse_event) = event.to_option() {
let x = cmp::max(0, cmp::min(self.display.width as i32, self.mouse_x + mouse_event.x));
let y = cmp::max(0, cmp::min(self.display.height as i32, self.mouse_y + mouse_event.y));
mouse_event.x = x;
self.mouse_x = x;
mouse_event.y = y;
self.mouse_y = y;
self.input.push_back(mouse_event.to_event());
} else {
self.input.push_back(*event);
}
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let mut i = 0;
let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::<Event>()) };
while i < event_buf.len() && ! self.input.is_empty() {
event_buf[i] = self.input.pop_front().unwrap();
i += 1;
}
Ok(i * mem::size_of::<Event>())
}
fn will_block(&self) -> bool {
self.input.is_empty()
}
fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
let size = cmp::max(0, cmp::min(self.display.offscreen.len() as isize - self.seek as isize, (buf.len()/4) as isize)) as usize;
if size > 0 {
unsafe {
fast_copy(self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4);
if sync {
fast_copy(self.display.onscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4);
}
}
}
Ok(size * 4)
}
fn seek(&mut self, pos: usize, whence: usize) -> Result<usize> {
let size = self.display.offscreen.len();
self.seek = match whence {
SEEK_SET => cmp::min(size, (pos/4)),
SEEK_CUR => cmp::max(0, cmp::min(size as isize, self.seek as isize + (pos/4) as isize)) as usize,
SEEK_END => cmp::max(0, cmp::min(size as isize, size as isize + (pos/4) as isize)) as usize,
_ => return Err(Error::new(EINVAL))
};
Ok(self.seek * 4)
}
fn sync(&mut self) {
self.redraw();
}
fn redraw(&mut self) {
let width = self.display.width;
let height = self.display.height;
self.display.sync(0, 0, width, height);
}
}

View file

@ -1,32 +0,0 @@
pub use self::graphic::GraphicScreen;
pub use self::text::TextScreen;
use orbclient::Event;
use syscall::Result;
mod graphic;
mod text;
pub trait Screen {
fn width(&self) -> usize;
fn height(&self) -> usize;
fn event(&mut self, flags: usize) -> Result<usize>;
fn map(&self, offset: usize, size: usize) -> Result<usize>;
fn input(&mut self, event: &Event);
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
fn will_block(&self) -> bool;
fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize>;
fn seek(&mut self, pos: usize, whence: usize) -> Result<usize>;
fn sync(&mut self);
fn redraw(&mut self);
}

View file

@ -1,233 +0,0 @@
extern crate ransid;
use std::collections::{BTreeSet, VecDeque};
use orbclient::{Event, EventOption};
use syscall::error::*;
use display::Display;
use screen::Screen;
pub struct TextScreen {
pub console: ransid::Console,
pub display: Display,
pub changed: BTreeSet<usize>,
pub ctrl: bool,
pub input: VecDeque<u8>,
pub end_of_input: bool,
pub cooked: VecDeque<u8>,
pub requested: usize
}
impl TextScreen {
pub fn new(display: Display) -> TextScreen {
TextScreen {
console: ransid::Console::new(display.width/8, display.height/16),
display: display,
changed: BTreeSet::new(),
ctrl: false,
input: VecDeque::new(),
end_of_input: false,
cooked: VecDeque::new(),
requested: 0
}
}
}
impl Screen for TextScreen {
fn width(&self) -> usize {
self.console.w
}
fn height(&self) -> usize {
self.console.h
}
fn event(&mut self, flags: usize) -> Result<usize> {
self.requested = flags;
Ok(0)
}
fn map(&self, offset: usize, size: usize) -> Result<usize> {
Err(Error::new(EBADF))
}
fn input(&mut self, event: &Event) {
let mut buf = vec![];
match event.to_option() {
EventOption::Key(key_event) => {
if key_event.scancode == 0x1D {
self.ctrl = key_event.pressed;
} else if key_event.pressed {
match key_event.scancode {
0x0E => { // Backspace
buf.extend_from_slice(b"\x7F");
},
0x47 => { // Home
buf.extend_from_slice(b"\x1B[H");
},
0x48 => { // Up
buf.extend_from_slice(b"\x1B[A");
},
0x49 => { // Page up
buf.extend_from_slice(b"\x1B[5~");
},
0x4B => { // Left
buf.extend_from_slice(b"\x1B[D");
},
0x4D => { // Right
buf.extend_from_slice(b"\x1B[C");
},
0x4F => { // End
buf.extend_from_slice(b"\x1B[F");
},
0x50 => { // Down
buf.extend_from_slice(b"\x1B[B");
},
0x51 => { // Page down
buf.extend_from_slice(b"\x1B[6~");
},
0x52 => { // Insert
buf.extend_from_slice(b"\x1B[2~");
},
0x53 => { // Delete
buf.extend_from_slice(b"\x1B[3~");
},
_ => {
let c = match key_event.character {
c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char,
c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char,
c => c
};
if c != '\0' {
buf.extend_from_slice(&[c as u8]);
}
}
}
}
},
_ => () //TODO: Mouse in terminal
}
if self.console.raw_mode {
for &b in buf.iter() {
self.input.push_back(b);
}
} else {
for &b in buf.iter() {
match b {
b'\x03' => {
self.end_of_input = true;
let _ = self.write(b"^C\n", true);
},
b'\x08' | b'\x7F' => {
if let Some(_c) = self.cooked.pop_back() {
let _ = self.write(b"\x08", true);
}
},
b'\x1B' => {
let _ = self.write(b"^[", true);
},
b'\n' | b'\r' => {
self.cooked.push_back(b);
while let Some(c) = self.cooked.pop_front() {
self.input.push_back(c);
}
let _ = self.write(b"\n", true);
},
_ => {
self.cooked.push_back(b);
let _ = self.write(&[b], true);
}
}
}
}
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let mut i = 0;
while i < buf.len() && ! self.input.is_empty() {
buf[i] = self.input.pop_front().unwrap();
i += 1;
}
if i == 0 {
self.end_of_input = false;
}
Ok(i)
}
fn will_block(&self) -> bool {
self.input.is_empty() && ! self.end_of_input
}
fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
let x = self.console.x;
let y = self.console.y;
self.display.invert(x * 8, y * 16, 8, 16);
self.changed.insert(y);
}
{
let display = &mut self.display;
let changed = &mut self.changed;
self.console.write(buf, |event| {
match event {
ransid::Event::Char { x, y, c, color, bold, .. } => {
display.char(x * 8, y * 16, c, color.data, bold, false);
changed.insert(y);
},
ransid::Event::Rect { x, y, w, h, color } => {
display.rect(x * 8, y * 16, w * 8, h * 16, color.data);
for y2 in y..y + h {
changed.insert(y2);
}
},
ransid::Event::Scroll { rows, color } => {
display.scroll(rows * 16, color.data);
for y in 0..display.height/16 {
changed.insert(y);
}
}
}
});
}
if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
let x = self.console.x;
let y = self.console.y;
self.display.invert(x * 8, y * 16, 8, 16);
self.changed.insert(y);
}
if ! self.console.raw_mode && sync {
self.sync();
}
Ok(buf.len())
}
fn seek(&mut self, _pos: usize, _whence: usize) -> Result<usize> {
Ok(0)
}
fn sync(&mut self) {
let width = self.display.width;
for change in self.changed.iter() {
self.display.sync(0, change * 16, width, 16);
}
self.changed.clear();
}
fn redraw(&mut self) {
let width = self.display.width;
let height = self.display.height;
self.display.sync(0, 0, width, height);
self.changed.clear();
}
}

1
isolinux Submodule

@ -0,0 +1 @@
Subproject commit 3cf79d335400af8fc3a87a13f0ae12777a766b3b

View file

@ -1,340 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

Binary file not shown.

View file

@ -1,6 +0,0 @@
prompt 0
default 1
label 1
kernel /isolinux/memdisk
append initrd=/livedisk.gz

Binary file not shown.

Binary file not shown.

2
kernel

@ -1 +1 @@
Subproject commit 882e64bdb976b365f055d3b0e225ced06dec8b49 Subproject commit 06118a23ddf578424c35c2a0f9b704acbc5648f0