commit
86c96b1b1d
9
.gitmodules
vendored
9
.gitmodules
vendored
|
@ -61,3 +61,12 @@
|
|||
[submodule "kernel"]
|
||||
path = kernel
|
||||
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
|
||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -5,10 +5,10 @@ rust:
|
|||
cache: cargo
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
matrix:
|
||||
allow_failures:
|
||||
- os: osx
|
||||
#- osx
|
||||
#matrix:
|
||||
# allow_failures:
|
||||
# - os: osx
|
||||
dist: trusty
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
||||
|
@ -26,7 +26,7 @@ before_install:
|
|||
script:
|
||||
- make clean &&
|
||||
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:
|
||||
email: false
|
||||
webhooks: http://37.139.9.28:54863/travis
|
||||
|
|
34
Cargo.toml
Normal file
34
Cargo.toml
Normal 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
108
Makefile
|
@ -37,38 +37,9 @@ iso: build/livedisk.iso
|
|||
FORCE:
|
||||
|
||||
clean:
|
||||
cargo clean
|
||||
cargo clean --manifest-path rust/src/libstd/Cargo.toml
|
||||
cargo clean --manifest-path kernel/Cargo.toml
|
||||
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/
|
||||
-$(FUMOUNT) build/filesystem/ || true
|
||||
rm -rf initfs/bin
|
||||
rm -rf filesystem/bin filesystem/sbin filesystem/ui/bin
|
||||
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/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:
|
||||
#cargo update --manifest-path rust/src/libstd/Cargo.toml
|
||||
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
|
||||
cargo update
|
||||
|
||||
pull:
|
||||
git pull --rebase --recurse-submodules
|
||||
|
@ -591,13 +499,13 @@ build/filesystem.bin: \
|
|||
filesystem/bin/sh \
|
||||
filesystem/bin/smith \
|
||||
filesystem/bin/tar
|
||||
-$(FUMOUNT) build/filesystem/
|
||||
-$(FUMOUNT) build/filesystem/ || true
|
||||
rm -rf $@ build/filesystem/
|
||||
dd if=/dev/zero of=$@ bs=1048576 count=64
|
||||
cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs-mkfs $@
|
||||
mkdir -p build/filesystem/
|
||||
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
|
||||
pgrep redoxfs
|
||||
cp -RL filesystem/* build/filesystem/
|
||||
|
@ -617,19 +525,19 @@ build/filesystem.bin: \
|
|||
mkdir build/filesystem/tmp
|
||||
chmod 1777 build/filesystem/tmp
|
||||
sync
|
||||
-$(FUMOUNT) build/filesystem/
|
||||
-$(FUMOUNT) build/filesystem/ || true
|
||||
rm -rf build/filesystem/
|
||||
|
||||
mount: FORCE
|
||||
mkdir -p build/filesystem/
|
||||
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
|
||||
pgrep redoxfs
|
||||
|
||||
unmount: FORCE
|
||||
sync
|
||||
-$(FUMOUNT) build/filesystem/
|
||||
-$(FUMOUNT) build/filesystem/ || true
|
||||
rm -rf build/filesystem/
|
||||
|
||||
wireshark: FORCE
|
||||
|
|
1
bootloader
Submodule
1
bootloader
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 7639aef32ed5ffd272701d955147b8b50aad53e0
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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:
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
1
drivers
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 9eeade88606095a03ee3c285972b45d1c499a971
|
|
@ -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/" }
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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); }
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
[package]
|
||||
name = "bgad"
|
||||
version = "0.1.0"
|
|
@ -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));
|
||||
}
|
|
@ -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/" }
|
|
@ -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 ...
|
||||
}
|
||||
}
|
|
@ -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); }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "pcid"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
redox_syscall = { path = "../../syscall/" }
|
||||
rustc-serialize = "0.3"
|
||||
toml = "0.2"
|
|
@ -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>>
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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] }
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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/" }
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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/" }
|
|
@ -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!(®s.tnpds as *const _ as usize - base, 0x20);
|
||||
assert_eq!(®s.cmd as *const _ as usize - base, 0x37);
|
||||
assert_eq!(®s.tcr as *const _ as usize - base, 0x40);
|
||||
assert_eq!(®s.rcr as *const _ as usize - base, 0x44);
|
||||
assert_eq!(®s.cmd_9346 as *const _ as usize - base, 0x50);
|
||||
assert_eq!(®s.phys_sts as *const _ as usize - base, 0x6C);
|
||||
assert_eq!(®s.rms as *const _ as usize - base, 0xDA);
|
||||
assert_eq!(®s.rdsar as *const _ as usize - base, 0xE4);
|
||||
assert_eq!(®s.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);
|
||||
}
|
||||
}
|
|
@ -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); }
|
||||
}
|
||||
}
|
|
@ -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 = []
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
|
@ -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");
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
1
isolinux
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 3cf79d335400af8fc3a87a13f0ae12777a766b3b
|
340
isolinux/COPYING
340
isolinux/COPYING
|
@ -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.
|
@ -1,6 +0,0 @@
|
|||
prompt 0
|
||||
default 1
|
||||
|
||||
label 1
|
||||
kernel /isolinux/memdisk
|
||||
append initrd=/livedisk.gz
|
Binary file not shown.
BIN
isolinux/memdisk
BIN
isolinux/memdisk
Binary file not shown.
2
kernel
2
kernel
|
@ -1 +1 @@
|
|||
Subproject commit 882e64bdb976b365f055d3b0e225ced06dec8b49
|
||||
Subproject commit 06118a23ddf578424c35c2a0f9b704acbc5648f0
|
Loading…
Reference in a new issue