commit
86c96b1b1d
9
.gitmodules
vendored
9
.gitmodules
vendored
|
@ -61,3 +61,12 @@
|
||||||
[submodule "kernel"]
|
[submodule "kernel"]
|
||||||
path = kernel
|
path = kernel
|
||||||
url = https://github.com/redox-os/kernel.git
|
url = https://github.com/redox-os/kernel.git
|
||||||
|
[submodule "drivers"]
|
||||||
|
path = drivers
|
||||||
|
url = https://github.com/redox-os/drivers.git
|
||||||
|
[submodule "bootloader"]
|
||||||
|
path = bootloader
|
||||||
|
url = https://github.com/redox-os/bootloader.git
|
||||||
|
[submodule "isolinux"]
|
||||||
|
path = isolinux
|
||||||
|
url = https://github.com/redox-os/isolinux.git
|
||||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -5,10 +5,10 @@ rust:
|
||||||
cache: cargo
|
cache: cargo
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
- osx
|
#- osx
|
||||||
matrix:
|
#matrix:
|
||||||
allow_failures:
|
# allow_failures:
|
||||||
- os: osx
|
# - os: osx
|
||||||
dist: trusty
|
dist: trusty
|
||||||
before_install:
|
before_install:
|
||||||
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
||||||
|
@ -26,7 +26,7 @@ before_install:
|
||||||
script:
|
script:
|
||||||
- make clean &&
|
- make clean &&
|
||||||
make update &&
|
make update &&
|
||||||
make build/harddrive.bin.gz build/livedisk.bin.gz build/livedisk.iso -j 2
|
make build/harddrive.bin.gz build/livedisk.bin.gz build/livedisk.iso
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
webhooks: http://37.139.9.28:54863/travis
|
webhooks: http://37.139.9.28:54863/travis
|
||||||
|
|
34
Cargo.toml
Normal file
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:
|
FORCE:
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
cargo clean
|
||||||
cargo clean --manifest-path rust/src/libstd/Cargo.toml
|
cargo clean --manifest-path rust/src/libstd/Cargo.toml
|
||||||
cargo clean --manifest-path kernel/Cargo.toml
|
-$(FUMOUNT) build/filesystem/ || true
|
||||||
cargo clean --manifest-path drivers/ahcid/Cargo.toml
|
|
||||||
cargo clean --manifest-path drivers/e1000d/Cargo.toml
|
|
||||||
cargo clean --manifest-path drivers/ps2d/Cargo.toml
|
|
||||||
cargo clean --manifest-path drivers/pcid/Cargo.toml
|
|
||||||
cargo clean --manifest-path drivers/rtl8168d/Cargo.toml
|
|
||||||
cargo clean --manifest-path drivers/vesad/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/acid/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/contain/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/init/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/ion/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/binutils/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/coreutils/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/extrautils/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/games/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/netutils/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/orbutils/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/pkgutils/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/userutils/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/smith/Cargo.toml
|
|
||||||
cargo clean --manifest-path programs/tar/Cargo.toml
|
|
||||||
cargo clean --manifest-path schemes/ethernetd/Cargo.toml
|
|
||||||
cargo clean --manifest-path schemes/example/Cargo.toml
|
|
||||||
cargo clean --manifest-path schemes/ipd/Cargo.toml
|
|
||||||
cargo clean --manifest-path schemes/orbital/Cargo.toml
|
|
||||||
cargo clean --manifest-path schemes/ptyd/Cargo.toml
|
|
||||||
cargo clean --manifest-path schemes/randd/Cargo.toml
|
|
||||||
cargo clean --manifest-path schemes/redoxfs/Cargo.toml
|
|
||||||
cargo clean --manifest-path schemes/tcpd/Cargo.toml
|
|
||||||
cargo clean --manifest-path schemes/udpd/Cargo.toml
|
|
||||||
-$(FUMOUNT) build/filesystem/
|
|
||||||
rm -rf initfs/bin
|
rm -rf initfs/bin
|
||||||
rm -rf filesystem/bin filesystem/sbin filesystem/ui/bin
|
rm -rf filesystem/bin filesystem/sbin filesystem/ui/bin
|
||||||
rm -rf build
|
rm -rf build
|
||||||
|
@ -92,71 +63,8 @@ ref: FORCE
|
||||||
cargo run --manifest-path crates/docgen/Cargo.toml -- programs/extrautils/src/bin/ filesystem/ref/
|
cargo run --manifest-path crates/docgen/Cargo.toml -- programs/extrautils/src/bin/ filesystem/ref/
|
||||||
cargo run --manifest-path crates/docgen/Cargo.toml -- programs/netutils/src/ filesystem/ref/
|
cargo run --manifest-path crates/docgen/Cargo.toml -- programs/netutils/src/ filesystem/ref/
|
||||||
|
|
||||||
test:
|
|
||||||
cargo test --manifest-path rust/src/libstd/Cargo.toml
|
|
||||||
cargo test --manifest-path kernel/Cargo.toml
|
|
||||||
cargo test --manifest-path drivers/ahcid/Cargo.toml
|
|
||||||
cargo test --manifest-path drivers/e1000d/Cargo.toml
|
|
||||||
cargo test --manifest-path drivers/ps2d/Cargo.toml
|
|
||||||
cargo test --manifest-path drivers/pcid/Cargo.toml
|
|
||||||
cargo test --manifest-path drivers/rtl8168d/Cargo.toml
|
|
||||||
cargo test --manifest-path drivers/vesad/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/acid/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/contain/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/init/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/ion/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/binutils/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/coreutils/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/extrautils/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/games/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/netutils/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/orbutils/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/pkgutils/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/userutils/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/smith/Cargo.toml
|
|
||||||
cargo test --manifest-path programs/tar/Cargo.toml
|
|
||||||
cargo test --manifest-path schemes/ethernetd/Cargo.toml
|
|
||||||
cargo test --manifest-path schemes/example/Cargo.toml
|
|
||||||
cargo test --manifest-path schemes/ipd/Cargo.toml
|
|
||||||
cargo test --manifest-path schemes/orbital/Cargo.toml
|
|
||||||
cargo test --manifest-path schemes/ptyd/Cargo.toml
|
|
||||||
cargo test --manifest-path schemes/randd/Cargo.toml
|
|
||||||
cargo test --manifest-path schemes/redoxfs/Cargo.toml
|
|
||||||
cargo test --manifest-path schemes/tcpd/Cargo.toml
|
|
||||||
cargo test --manifest-path schemes/udpd/Cargo.toml
|
|
||||||
|
|
||||||
update:
|
update:
|
||||||
#cargo update --manifest-path rust/src/libstd/Cargo.toml
|
cargo update
|
||||||
cargo update --manifest-path kernel/Cargo.toml
|
|
||||||
cargo update --manifest-path drivers/ahcid/Cargo.toml
|
|
||||||
cargo update --manifest-path drivers/e1000d/Cargo.toml
|
|
||||||
cargo update --manifest-path drivers/ps2d/Cargo.toml
|
|
||||||
cargo update --manifest-path drivers/pcid/Cargo.toml
|
|
||||||
cargo update --manifest-path drivers/rtl8168d/Cargo.toml
|
|
||||||
cargo update --manifest-path drivers/vesad/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/acid/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/contain/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/init/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/ion/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/binutils/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/coreutils/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/extrautils/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/games/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/netutils/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/orbutils/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/pkgutils/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/userutils/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/smith/Cargo.toml
|
|
||||||
cargo update --manifest-path programs/tar/Cargo.toml
|
|
||||||
cargo update --manifest-path schemes/ethernetd/Cargo.toml
|
|
||||||
cargo update --manifest-path schemes/example/Cargo.toml
|
|
||||||
cargo update --manifest-path schemes/ipd/Cargo.toml
|
|
||||||
cargo update --manifest-path schemes/orbital/Cargo.toml
|
|
||||||
cargo update --manifest-path schemes/ptyd/Cargo.toml
|
|
||||||
cargo update --manifest-path schemes/randd/Cargo.toml
|
|
||||||
cargo update --manifest-path schemes/redoxfs/Cargo.toml
|
|
||||||
cargo update --manifest-path schemes/tcpd/Cargo.toml
|
|
||||||
cargo update --manifest-path schemes/udpd/Cargo.toml
|
|
||||||
|
|
||||||
pull:
|
pull:
|
||||||
git pull --rebase --recurse-submodules
|
git pull --rebase --recurse-submodules
|
||||||
|
@ -591,13 +499,13 @@ build/filesystem.bin: \
|
||||||
filesystem/bin/sh \
|
filesystem/bin/sh \
|
||||||
filesystem/bin/smith \
|
filesystem/bin/smith \
|
||||||
filesystem/bin/tar
|
filesystem/bin/tar
|
||||||
-$(FUMOUNT) build/filesystem/
|
-$(FUMOUNT) build/filesystem/ || true
|
||||||
rm -rf $@ build/filesystem/
|
rm -rf $@ build/filesystem/
|
||||||
dd if=/dev/zero of=$@ bs=1048576 count=64
|
dd if=/dev/zero of=$@ bs=1048576 count=64
|
||||||
cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs-mkfs $@
|
cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs-mkfs $@
|
||||||
mkdir -p build/filesystem/
|
mkdir -p build/filesystem/
|
||||||
cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs
|
cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs
|
||||||
schemes/redoxfs/target/release/redoxfs $@ build/filesystem/
|
cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs -- $@ build/filesystem/
|
||||||
sleep 2
|
sleep 2
|
||||||
pgrep redoxfs
|
pgrep redoxfs
|
||||||
cp -RL filesystem/* build/filesystem/
|
cp -RL filesystem/* build/filesystem/
|
||||||
|
@ -617,19 +525,19 @@ build/filesystem.bin: \
|
||||||
mkdir build/filesystem/tmp
|
mkdir build/filesystem/tmp
|
||||||
chmod 1777 build/filesystem/tmp
|
chmod 1777 build/filesystem/tmp
|
||||||
sync
|
sync
|
||||||
-$(FUMOUNT) build/filesystem/
|
-$(FUMOUNT) build/filesystem/ || true
|
||||||
rm -rf build/filesystem/
|
rm -rf build/filesystem/
|
||||||
|
|
||||||
mount: FORCE
|
mount: FORCE
|
||||||
mkdir -p build/filesystem/
|
mkdir -p build/filesystem/
|
||||||
cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs
|
cargo build --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs
|
||||||
schemes/redoxfs/target/release/redoxfs build/harddrive.bin build/filesystem/
|
cargo run --manifest-path schemes/redoxfs/Cargo.toml --release --bin redoxfs -- build/harddrive.bin build/filesystem/
|
||||||
sleep 2
|
sleep 2
|
||||||
pgrep redoxfs
|
pgrep redoxfs
|
||||||
|
|
||||||
unmount: FORCE
|
unmount: FORCE
|
||||||
sync
|
sync
|
||||||
-$(FUMOUNT) build/filesystem/
|
-$(FUMOUNT) build/filesystem/ || true
|
||||||
rm -rf build/filesystem/
|
rm -rf build/filesystem/
|
||||||
|
|
||||||
wireshark: FORCE
|
wireshark: FORCE
|
||||||
|
|
1
bootloader
Submodule
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