serial: unify 8250 drivers, better dts support

This commit is contained in:
2026-01-16 23:18:46 +02:00
parent 21a8361eec
commit 195c19e225
83 changed files with 3191 additions and 5600 deletions
Generated
+43 -10
View File
@@ -1199,9 +1199,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.169"
version = "0.2.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
dependencies = [
"rustc-std-workspace-core",
]
@@ -1353,6 +1353,12 @@ version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "litemap"
version = "0.7.4"
@@ -1787,7 +1793,20 @@ dependencies = [
"bitflags 2.8.0",
"errno",
"libc",
"linux-raw-sys",
"linux-raw-sys 0.4.15",
"windows-sys",
]
[[package]]
name = "rustix"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
dependencies = [
"bitflags 2.8.0",
"errno",
"libc",
"linux-raw-sys 0.11.0",
"windows-sys",
]
@@ -2004,15 +2023,14 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.16.0"
version = "3.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
dependencies = [
"cfg-if",
"fastrand",
"getrandom 0.3.1",
"once_cell",
"rustix",
"rustix 1.1.3",
"windows-sys",
]
@@ -2388,7 +2406,7 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
dependencies = [
"either",
"home",
"rustix",
"rustix 0.38.44",
"winsafe",
]
@@ -2557,8 +2575,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909"
dependencies = [
"libc",
"linux-raw-sys",
"rustix",
"linux-raw-sys 0.4.15",
"rustix 0.38.44",
]
[[package]]
@@ -2589,6 +2607,7 @@ dependencies = [
"semver 1.0.25",
"serde",
"tar",
"tempfile",
"thiserror",
"toml",
"walkdir",
@@ -2855,6 +2874,19 @@ dependencies = [
"yggdrasil-abi",
]
[[package]]
name = "ygg_driver_serial_8250"
version = "0.1.0"
dependencies = [
"device-api",
"device-tree",
"kernel-arch-x86",
"libk",
"libk-mm",
"libk-util",
"yggdrasil-abi",
]
[[package]]
name = "ygg_driver_usb"
version = "0.1.0"
@@ -3028,6 +3060,7 @@ dependencies = [
"ygg_driver_net_stmmac",
"ygg_driver_nvme",
"ygg_driver_pci",
"ygg_driver_serial_8250",
"ygg_driver_usb",
"ygg_driver_usb_xhci",
"ygg_driver_virtio_blk",
+3 -2
View File
@@ -33,10 +33,11 @@ $ booti ${loadaddr} ${initrd_addr_r}:<initrd-size> ${fdt_addr_r}
env set ipaddr 13.0.0.2; env set initrd_addr_r 0x70000000; tftpboot ${initrd_addr_r} 13.0.0.1:initrd.img; tftpboot ${loadaddr} 13.0.0.1:yggdrasil-kernel.bin; load mmc 1:3 ${fdt_addr_r} dtbs/6.6.20-starfive/starfive/${fdtfile}; fdt resize; booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
env set ipaddr 13.0.0.2; env set initrd_addr_r 0x70000000; tftpboot ${initrd_addr_r} 13.0.0.1:initrd.img; tftpboot ${loadaddr} 13.0.0.1:yggdrasil-kernel.bin; tftpboot ${fdt_addr_r} 13.0.0.1:vf2.dtb; fdt resize; booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
#### For DHCP boot with BUILD-MACHINE-IP-ADDR 192.168.88.10
dhcp
dhcp; env set initrd_addr_r 0x70000000; tftpboot ${initrd_addr_r} 192.168.88.10:initrd.img; tftpboot ${loadaddr} 192.168.88.10:yggdrasil-kernel.bin; load mmc 1:3 ${fdt_addr_r} dtbs/6.6.20-starfive/starfive/${fdtfile}; fdt resize; booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
dhcp; env set initrd_addr_r 0x70000000; tftpboot ${initrd_addr_r} 192.168.88.10:initrd.img; tftpboot ${loadaddr} 192.168.88.10:yggdrasil-kernel.bin; tftpboot ${fdt_addr_r} 192.168.88.10:vf2.dtb; fdt resize; booti ${loadaddr} ${initrd_addr_r}:60000000 ${fdt_addr_r}
Missing drivers:
Binary file not shown.
@@ -264,16 +264,15 @@
compatible = "gpio-keys";
poweroff {
gpios = <0x8007 0x03 0x00>;
gpios = <&gpio 0x03 0x00>;
linux,code = <0x74>;
label = "GPIO Key Poweroff";
};
};
pl061@9030000 {
phandle = <0x8007>;
gpio: pl061@9030000 {
clock-names = "apb_pclk";
clocks = <0x8000>;
clocks = <&clk_24mhz>;
interrupts = <0x00 0x07 0x04>;
gpio-controller;
#gpio-cells = <0x02>;
@@ -299,15 +298,15 @@
pl031@9010000 {
clock-names = "apb_pclk";
clocks = <0x8000>;
clocks = <&clk_24mhz>;
interrupts = <0x00 0x02 0x04>;
reg = <0x00 0x9010000 0x00 0x1000>;
compatible = "arm,pl031", "arm,primecell";
};
pl011@9000000 {
uart0: pl011@9000000 {
clock-names = "uartclk", "apb_pclk";
clocks = <0x8000 0x8000>;
clocks = <&clk_24mhz &clk_24mhz>;
interrupts = <0x00 0x01 0x04>;
reg = <0x00 0x9000000 0x00 0x1000>;
compatible = "arm,pl011", "arm,primecell";
@@ -411,8 +410,7 @@
compatible = "arm,armv8-timer", "arm,armv7-timer";
};
apb-pclk {
phandle = <0x8000>;
clk_24mhz: apb-pclk {
clock-output-names = "clk24mhz";
clock-frequency = <0x16e3600>;
#clock-cells = <0x00>;
+492
View File
@@ -0,0 +1,492 @@
/dts-v1/;
#include <aarch64/gicv2.h>
/memreserve/ 0x0000000000000000 0x0000000000001000;
/ {
compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
model = "Raspberry Pi 4 Model B";
#address-cells = <0x02>;
#size-cells = <0x01>;
interrupt-parent = <&gicv2>;
aliases {
serial0 = "/soc/serial@7e201000";
serial1 = "/soc/serial@7e215040";
blconfig = "/reserved-memory/nvram@0";
};
chosen {
stdout-path = "serial1:115200n8";
};
reserved-memory {
#address-cells = <0x02>;
#size-cells = <0x01>;
ranges;
linux,cma {
compatible = "shared-dma-pool";
size = <0x4000000>;
reusable;
linux,cma-default;
alloc-ranges = <0x00 0x00 0x40000000>;
};
nvram@0 {
compatible = "raspberrypi,bootloader-config", "nvmem-rmem";
#address-cells = <0x01>;
#size-cells = <0x01>;
reg = <0x00 0x00 0x00>;
no-map;
status = "disabled";
};
};
soc {
compatible = "simple-bus";
#address-cells = <0x01>;
#size-cells = <0x01>;
ranges = <0x7e000000 0x00 0xfe000000 0x01800000>,
<0x7c000000 0x00 0xfc000000 0x02000000>,
<0x40000000 0x00 0xff800000 0x00800000>;
dma-ranges = <0xc0000000 0x00 0x00 0x40000000>;
timer@7e003000 {
compatible = "brcm,bcm2835-system-timer";
reg = <0x7e003000 0x1000>;
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <0xf4240>;
};
txp@7e004000 {
compatible = "brcm,bcm2835-txp";
reg = <0x7e004000 0x20>;
interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
};
dsi0: dsi@7e209000 {
compatible = "brcm,bcm2835-dsi0";
reg = <0x7e209000 0x78>;
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <0x01>;
#size-cells = <0x00>;
#clock-cells = <0x01>;
clocks = <&cprman 0x20>,
<&cprman 0x2f>,
<&cprman 0x31>;
clock-names = "phy", "escape", "pixel";
clock-output-names = "dsi0_byte", "dsi0_ddr2", "dsi0_ddr";
status = "disabled";
power-domains = <&power 0x11>;
};
dsi1: dsi@7e700000 {
compatible = "brcm,bcm2711-dsi1";
reg = <0x7e700000 0x8c>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <0x01>;
#size-cells = <0x00>;
#clock-cells = <0x01>;
clocks = <&cprman 0x23>,
<&cprman 0x30>,
<&cprman 0x32>;
clock-names = "phy", "escape", "pixel";
clock-output-names = "dsi1_byte", "dsi1_ddr2", "dsi1_ddr";
status = "disabled";
power-domains = <&power 0x12>;
};
cprman: cprman@7e101000 {
compatible = "brcm,bcm2711-cprman";
#clock-cells = <0x01>;
reg = <0x7e101000 0x2000>;
clocks = <&clk_osc>,
<&dsi0 0x00>,
<&dsi0 0x01>,
<&dsi0 0x02>,
<&dsi1 0x00>,
<&dsi1 0x01>,
<&dsi1 0x02>;
};
mbox: mailbox@7e00b880 {
compatible = "brcm,bcm2835-mbox";
reg = <0x7e00b880 0x40>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
#mbox-cells = <0x00>;
};
gpio: gpio@7e200000 {
compatible = "brcm,bcm2711-gpio";
reg = <0x7e200000 0xb4>;
interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <0x02>;
interrupt-controller;
#interrupt-cells = <0x02>;
pinctrl-names = "default";
bootph-all;
uart0_ctsrts_gpio30: uart0_ctsrts_gpio30 {
brcm,pins = <30>, <31>;
brcm,pull = <2>, <0>;
brcm,function = <7>;
};
uart0_gpio32: uart0_gpio32 {
brcm,pins = <32>, <33>;
brcm,pull = <0>, <2>;
brcm,function = <8>;
};
uart1_gpio14: uart1_gpio14 {
brcm,pins = <14>, <15>;
brcm,function = <2>;
bootph-all;
};
};
uart0: serial@7e201000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x7e201000 0x200>;
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cprman 0x13>,
<&cprman 0x14>;
clock-names = "uartclk",
"apb_pclk";
arm,primecell-periphid = <0x241011>;
pinctrl-names = "default";
pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32>;
uart-has-rtscts;
status = "okay";
skip-init;
bootph-all;
};
aux: aux@7e215000 {
compatible = "brcm,bcm2835-aux";
#clock-cells = <0x01>;
reg = <0x7e215000 0x08>;
clocks = <&cprman 0x14>;
};
uart1: serial@7e215040 {
compatible = "brcm,bcm2835-aux-uart";
reg = <0x7e215040 0x40>;
interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&aux 0x00>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart1_gpio14>;
skip-init;
bootph-all;
};
l1_intc: local_intc@40000000 {
compatible = "brcm,bcm2836-l1-intc";
reg = <0x40000000 0x100>;
};
gicv2: interrupt-controller@40041000 {
interrupt-controller;
#interrupt-cells = <0x03>;
compatible = "arm,gic-400";
reg = <0x40041000 0x1000>,
<0x40042000 0x2000>,
<0x40044000 0x2000>,
<0x40046000 0x2000>;
interrupts = <GIC_PPI 9 (IRQ_TYPE_LEVEL_HIGH | GIC_CPU_MASK_SIMPLE(4))>;
};
avs_monitor: avs-monitor@7d5d2000 {
compatible = "brcm,bcm2711-avs-monitor", "syscon", "simple-mfd";
reg = <0x7d5d2000 0xf00>;
};
dma: dma@7e007000 {
compatible = "brcm,bcm2835-dma";
reg = <0x7e007000 0xb00>;
interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "dma0",
"dma1",
"dma2",
"dma3",
"dma4",
"dma5",
"dma6",
"dma7",
"dma8",
"dma9",
"dma10";
#dma-cells = <0x01>;
brcm,dma-channel-mask = <0x7f5>;
};
pm_wdt: watchdog@7e100000 {
compatible = "brcm,bcm2835-pm", "brcm,bcm2835-pm-wdt";
#power-domain-cells = <0x01>;
#reset-cells = <0x01>;
reg = <0x7e100000 0x114>,
<0x7e00a000 0x24>,
<0x7ec11000 0x20>;
clocks = <&cprman 0x15>,
<&cprman 0x1d>,
<&cprman 0x17>,
<&cprman 0x16>;
clock-names = "v3d", "peri_image", "h264", "isp";
system-power-controller;
};
uart2: serial@7e201400 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x7e201400 0x200>;
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cprman 0x13>,
<&cprman 0x14>;
clock-names = "uartclk",
"apb_pclk";
arm,primecell-periphid = <0x241011>;
status = "disabled";
};
uart3: serial@7e201600 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x7e201600 0x200>;
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cprman 0x13>,
<&cprman 0x14>;
clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x241011>;
status = "disabled";
};
uart4: serial@7e201800 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x7e201800 0x200>;
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cprman 0x13>,
<&cprman 0x14>;
clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x241011>;
status = "disabled";
};
uart5: serial@7e201a00 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x7e201a00 0x200>;
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cprman 0x13>,
<&cprman 0x14>;
clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x241011>;
status = "disabled";
};
clk_dvp: clock@7ef00000 {
compatible = "brcm,brcm2711-dvp";
reg = <0x7ef00000 0x10>;
clocks = <&clk_108m>;
#clock-cells = <0x01>;
#reset-cells = <0x01>;
};
l2_intc: interrupt-controller@7ef00100 {
compatible = "brcm,bcm2711-l2-intc", "brcm,l2-intc";
reg = <0x7ef00100 0x30>;
interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <0x01>;
};
firmware: firmware {
compatible = "raspberrypi,bcm2835-firmware", "simple-mfd";
#address-cells = <0x01>;
#size-cells = <0x01>;
mboxes = <&mbox>;
dma-ranges;
clk_firmware: clocks {
compatible = "raspberrypi,firmware-clocks";
#clock-cells = <0x01>;
};
gpio_firmware: gpio {
compatible = "raspberrypi,firmware-gpio";
gpio-controller;
#gpio-cells = <0x02>;
status = "okay";
gpio-line-names = "BT_ON", "WL_ON", "PWR_LED_OFF", "GLOBAL_RESET", "VDD_SD_IO_SEL", "CAM_GPIO", "SD_PWR_ON", "";
};
firmware_reset: reset {
compatible = "raspberrypi,firmware-reset";
#reset-cells = <0x01>;
};
};
power: power {
compatible = "raspberrypi,bcm2835-power";
firmware = <&firmware>;
#power-domain-cells = <0x01>;
};
vchiq: mailbox@7e00b840 {
compatible = "brcm,bcm2835-vchiq";
reg = <0x7e00b840 0x3c>;
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
};
};
clocks {
clk_osc: clk-osc {
compatible = "fixed-clock";
#clock-cells = <0x00>;
clock-output-names = "osc";
clock-frequency = <54000000>;
};
clk_usb: clk-usb {
compatible = "fixed-clock";
#clock-cells = <0x00>;
clock-output-names = "otg";
clock-frequency = <480000000>;
};
};
clk_27m: clk-27M {
#clock-cells = <0x00>;
compatible = "fixed-clock";
clock-frequency = <27000000>;
clock-output-names = "27MHz-clock";
};
clk_108m: clk-108M {
#clock-cells = <0x00>;
compatible = "fixed-clock";
clock-frequency = <108000000>;
clock-output-names = "108MHz-clock";
};
pmu: arm-pmu {
compatible = "arm,cortex-a72-pmu", "arm,armv8-pmuv3";
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
interrupt-affinity = <0x21>,
<0x22>,
<0x23>,
<0x24>;
};
arm_timer: timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 15 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 16 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
arm,cpu-registers-not-fw-configured;
};
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
enable-method = "brcm,bcm2836-smp";
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a72";
reg = <0x00>;
enable-method = "spin-table";
cpu-release-addr = <0x00 0xd8>;
};
cpu1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a72";
reg = <0x01>;
enable-method = "spin-table";
cpu-release-addr = <0x00 0xe0>;
};
cpu2: cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a72";
reg = <0x02>;
enable-method = "spin-table";
cpu-release-addr = <0x00 0xe8>;
};
cpu3: cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a72";
reg = <0x03>;
enable-method = "spin-table";
cpu-release-addr = <0x00 0xf0>;
};
};
leds {
compatible = "gpio-leds";
led_act: led-act {
label = "ACT";
default-state = "keep";
linux,default-trigger = "heartbeat";
gpios = <&gpio 0x2a 0x00>;
};
led_pwr: led-pwr {
label = "PWR";
gpios = <&gpio_firmware 0x02 0x01>;
default-state = "keep";
linux,default-trigger = "default-on";
};
};
memory@0 {
device_type = "memory";
reg = <0x00 0x00 0x00>;
};
sd_io_1v8_reg {
compatible = "regulator-gpio";
regulator-name = "vdd-sd-io";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-always-on;
regulator-settling-time-us = <0x1388>;
gpios = <&gpio_firmware 0x04 0x00>;
states = <3300000 0x01>,
<1800000 0x00>;
status = "okay";
};
sd_vcc_reg {
compatible = "regulator-fixed";
regulator-name = "vcc-sd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
enable-active-high;
gpio = <&gpio_firmware 0x06 0x00>;
};
};
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#define GIC_SPI 0
#define GIC_PPI 1
#define GIC_CPU_MASK_RAW(x) ((x) << 8)
#define GIC_CPU_MASK_SIMPLE(num) GIC_CPU_MASK_RAW((1 << (num)) - 1)
#define IRQ_TYPE_NONE 0
#define IRQ_TYPE_EDGE_RISING 1
#define IRQ_TYPE_EDGE_FALLING 2
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)
#define IRQ_TYPE_LEVEL_HIGH 4
#define IRQ_TYPE_LEVEL_LOW 8
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
+308
View File
@@ -0,0 +1,308 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Copyright (C) 2022 Emil Renner Berthing <kernel@esmil.dk>
* Copyright (C) 2022 StarFive Technology Co., Ltd.
*/
#ifndef __JH7110_PINFUNC_H__
#define __JH7110_PINFUNC_H__
/*
* mux bits:
* | 31 - 24 | 23 - 16 | 15 - 10 | 9 - 8 | 7 - 0 |
* | din | dout | doen | function | gpio nr |
*
* dout: output signal
* doen: output enable signal
* din: optional input signal, 0xff = none
* function: function selector
* gpio nr: gpio number, 0 - 63
*/
#define GPIOMUX(n, dout, doen, din) ( \
(((din) & 0xff) << 24) | \
(((dout) & 0xff) << 16) | \
(((doen) & 0x3f) << 10) | \
((n) & 0x3f))
#define PINMUX(n, func) ((1 << 10) | (((func) & 0x3) << 8) | ((n) & 0xff))
/* sys_iomux dout */
#define GPOUT_LOW 0
#define GPOUT_HIGH 1
#define GPOUT_SYS_WAVE511_UART_TX 2
#define GPOUT_SYS_CAN0_STBY 3
#define GPOUT_SYS_CAN0_TST_NEXT_BIT 4
#define GPOUT_SYS_CAN0_TST_SAMPLE_POINT 5
#define GPOUT_SYS_CAN0_TXD 6
#define GPOUT_SYS_USB_DRIVE_VBUS 7
#define GPOUT_SYS_QSPI_CS1 8
#define GPOUT_SYS_SPDIF 9
#define GPOUT_SYS_HDMI_CEC_SDA 10
#define GPOUT_SYS_HDMI_DDC_SCL 11
#define GPOUT_SYS_HDMI_DDC_SDA 12
#define GPOUT_SYS_WATCHDOG 13
#define GPOUT_SYS_I2C0_CLK 14
#define GPOUT_SYS_I2C0_DATA 15
#define GPOUT_SYS_SDIO0_BACK_END_POWER 16
#define GPOUT_SYS_SDIO0_CARD_POWER_EN 17
#define GPOUT_SYS_SDIO0_CCMD_OD_PULLUP_EN 18
#define GPOUT_SYS_SDIO0_RST 19
#define GPOUT_SYS_UART0_TX 20
#define GPOUT_SYS_HIFI4_JTAG_TDO 21
#define GPOUT_SYS_JTAG_TDO 22
#define GPOUT_SYS_PDM_MCLK 23
#define GPOUT_SYS_PWM_CHANNEL0 24
#define GPOUT_SYS_PWM_CHANNEL1 25
#define GPOUT_SYS_PWM_CHANNEL2 26
#define GPOUT_SYS_PWM_CHANNEL3 27
#define GPOUT_SYS_PWMDAC_LEFT 28
#define GPOUT_SYS_PWMDAC_RIGHT 29
#define GPOUT_SYS_SPI0_CLK 30
#define GPOUT_SYS_SPI0_FSS 31
#define GPOUT_SYS_SPI0_TXD 32
#define GPOUT_SYS_GMAC_PHYCLK 33
#define GPOUT_SYS_I2SRX_BCLK 34
#define GPOUT_SYS_I2SRX_LRCK 35
#define GPOUT_SYS_I2STX0_BCLK 36
#define GPOUT_SYS_I2STX0_LRCK 37
#define GPOUT_SYS_MCLK 38
#define GPOUT_SYS_TDM_CLK 39
#define GPOUT_SYS_TDM_SYNC 40
#define GPOUT_SYS_TDM_TXD 41
#define GPOUT_SYS_TRACE_DATA0 42
#define GPOUT_SYS_TRACE_DATA1 43
#define GPOUT_SYS_TRACE_DATA2 44
#define GPOUT_SYS_TRACE_DATA3 45
#define GPOUT_SYS_TRACE_REF 46
#define GPOUT_SYS_CAN1_STBY 47
#define GPOUT_SYS_CAN1_TST_NEXT_BIT 48
#define GPOUT_SYS_CAN1_TST_SAMPLE_POINT 49
#define GPOUT_SYS_CAN1_TXD 50
#define GPOUT_SYS_I2C1_CLK 51
#define GPOUT_SYS_I2C1_DATA 52
#define GPOUT_SYS_SDIO1_BACK_END_POWER 53
#define GPOUT_SYS_SDIO1_CARD_POWER_EN 54
#define GPOUT_SYS_SDIO1_CLK 55
#define GPOUT_SYS_SDIO1_CMD_OD_PULLUP_EN 56
#define GPOUT_SYS_SDIO1_CMD 57
#define GPOUT_SYS_SDIO1_DATA0 58
#define GPOUT_SYS_SDIO1_DATA1 59
#define GPOUT_SYS_SDIO1_DATA2 60
#define GPOUT_SYS_SDIO1_DATA3 61
#define GPOUT_SYS_SDIO1_DATA4 62
#define GPOUT_SYS_SDIO1_DATA5 63
#define GPOUT_SYS_SDIO1_DATA6 64
#define GPOUT_SYS_SDIO1_DATA7 65
#define GPOUT_SYS_SDIO1_RST 66
#define GPOUT_SYS_UART1_RTS 67
#define GPOUT_SYS_UART1_TX 68
#define GPOUT_SYS_I2STX1_SDO0 69
#define GPOUT_SYS_I2STX1_SDO1 70
#define GPOUT_SYS_I2STX1_SDO2 71
#define GPOUT_SYS_I2STX1_SDO3 72
#define GPOUT_SYS_SPI1_CLK 73
#define GPOUT_SYS_SPI1_FSS 74
#define GPOUT_SYS_SPI1_TXD 75
#define GPOUT_SYS_I2C2_CLK 76
#define GPOUT_SYS_I2C2_DATA 77
#define GPOUT_SYS_UART2_RTS 78
#define GPOUT_SYS_UART2_TX 79
#define GPOUT_SYS_SPI2_CLK 80
#define GPOUT_SYS_SPI2_FSS 81
#define GPOUT_SYS_SPI2_TXD 82
#define GPOUT_SYS_I2C3_CLK 83
#define GPOUT_SYS_I2C3_DATA 84
#define GPOUT_SYS_UART3_TX 85
#define GPOUT_SYS_SPI3_CLK 86
#define GPOUT_SYS_SPI3_FSS 87
#define GPOUT_SYS_SPI3_TXD 88
#define GPOUT_SYS_I2C4_CLK 89
#define GPOUT_SYS_I2C4_DATA 90
#define GPOUT_SYS_UART4_RTS 91
#define GPOUT_SYS_UART4_TX 92
#define GPOUT_SYS_SPI4_CLK 93
#define GPOUT_SYS_SPI4_FSS 94
#define GPOUT_SYS_SPI4_TXD 95
#define GPOUT_SYS_I2C5_CLK 96
#define GPOUT_SYS_I2C5_DATA 97
#define GPOUT_SYS_UART5_RTS 98
#define GPOUT_SYS_UART5_TX 99
#define GPOUT_SYS_SPI5_CLK 100
#define GPOUT_SYS_SPI5_FSS 101
#define GPOUT_SYS_SPI5_TXD 102
#define GPOUT_SYS_I2C6_CLK 103
#define GPOUT_SYS_I2C6_DATA 104
#define GPOUT_SYS_SPI6_CLK 105
#define GPOUT_SYS_SPI6_FSS 106
#define GPOUT_SYS_SPI6_TXD 107
/* aon_iomux dout */
#define GPOUT_AON_CLK_32K_OUT 2
#define GPOUT_AON_PTC0_PWM4 3
#define GPOUT_AON_PTC0_PWM5 4
#define GPOUT_AON_PTC0_PWM6 5
#define GPOUT_AON_PTC0_PWM7 6
#define GPOUT_AON_CLK_GCLK0 7
#define GPOUT_AON_CLK_GCLK1 8
#define GPOUT_AON_CLK_GCLK2 9
/* sys_iomux doen */
#define GPOEN_ENABLE 0
#define GPOEN_DISABLE 1
#define GPOEN_SYS_HDMI_CEC_SDA 2
#define GPOEN_SYS_HDMI_DDC_SCL 3
#define GPOEN_SYS_HDMI_DDC_SDA 4
#define GPOEN_SYS_I2C0_CLK 5
#define GPOEN_SYS_I2C0_DATA 6
#define GPOEN_SYS_HIFI4_JTAG_TDO 7
#define GPOEN_SYS_JTAG_TDO 8
#define GPOEN_SYS_PWM0_CHANNEL0 9
#define GPOEN_SYS_PWM0_CHANNEL1 10
#define GPOEN_SYS_PWM0_CHANNEL2 11
#define GPOEN_SYS_PWM0_CHANNEL3 12
#define GPOEN_SYS_SPI0_NSSPCTL 13
#define GPOEN_SYS_SPI0_NSSP 14
#define GPOEN_SYS_TDM_SYNC 15
#define GPOEN_SYS_TDM_TXD 16
#define GPOEN_SYS_I2C1_CLK 17
#define GPOEN_SYS_I2C1_DATA 18
#define GPOEN_SYS_SDIO1_CMD 19
#define GPOEN_SYS_SDIO1_DATA0 20
#define GPOEN_SYS_SDIO1_DATA1 21
#define GPOEN_SYS_SDIO1_DATA2 22
#define GPOEN_SYS_SDIO1_DATA3 23
#define GPOEN_SYS_SDIO1_DATA4 24
#define GPOEN_SYS_SDIO1_DATA5 25
#define GPOEN_SYS_SDIO1_DATA6 26
#define GPOEN_SYS_SDIO1_DATA7 27
#define GPOEN_SYS_SPI1_NSSPCTL 28
#define GPOEN_SYS_SPI1_NSSP 29
#define GPOEN_SYS_I2C2_CLK 30
#define GPOEN_SYS_I2C2_DATA 31
#define GPOEN_SYS_SPI2_NSSPCTL 32
#define GPOEN_SYS_SPI2_NSSP 33
#define GPOEN_SYS_I2C3_CLK 34
#define GPOEN_SYS_I2C3_DATA 35
#define GPOEN_SYS_SPI3_NSSPCTL 36
#define GPOEN_SYS_SPI3_NSSP 37
#define GPOEN_SYS_I2C4_CLK 38
#define GPOEN_SYS_I2C4_DATA 39
#define GPOEN_SYS_SPI4_NSSPCTL 40
#define GPOEN_SYS_SPI4_NSSP 41
#define GPOEN_SYS_I2C5_CLK 42
#define GPOEN_SYS_I2C5_DATA 43
#define GPOEN_SYS_SPI5_NSSPCTL 44
#define GPOEN_SYS_SPI5_NSSP 45
#define GPOEN_SYS_I2C6_CLK 46
#define GPOEN_SYS_I2C6_DATA 47
#define GPOEN_SYS_SPI6_NSSPCTL 48
#define GPOEN_SYS_SPI6_NSSP 49
/* aon_iomux doen */
#define GPOEN_AON_PTC0_OE_N_4 2
#define GPOEN_AON_PTC0_OE_N_5 3
#define GPOEN_AON_PTC0_OE_N_6 4
#define GPOEN_AON_PTC0_OE_N_7 5
/* sys_iomux gin */
#define GPI_NONE 255
#define GPI_SYS_WAVE511_UART_RX 0
#define GPI_SYS_CAN0_RXD 1
#define GPI_SYS_USB_OVERCURRENT 2
#define GPI_SYS_SPDIF 3
#define GPI_SYS_JTAG_RST 4
#define GPI_SYS_HDMI_CEC_SDA 5
#define GPI_SYS_HDMI_DDC_SCL 6
#define GPI_SYS_HDMI_DDC_SDA 7
#define GPI_SYS_HDMI_HPD 8
#define GPI_SYS_I2C0_CLK 9
#define GPI_SYS_I2C0_DATA 10
#define GPI_SYS_SDIO0_CD 11
#define GPI_SYS_SDIO0_INT 12
#define GPI_SYS_SDIO0_WP 13
#define GPI_SYS_UART0_RX 14
#define GPI_SYS_HIFI4_JTAG_TCK 15
#define GPI_SYS_HIFI4_JTAG_TDI 16
#define GPI_SYS_HIFI4_JTAG_TMS 17
#define GPI_SYS_HIFI4_JTAG_RST 18
#define GPI_SYS_JTAG_TDI 19
#define GPI_SYS_JTAG_TMS 20
#define GPI_SYS_PDM_DMIC0 21
#define GPI_SYS_PDM_DMIC1 22
#define GPI_SYS_I2SRX_SDIN0 23
#define GPI_SYS_I2SRX_SDIN1 24
#define GPI_SYS_I2SRX_SDIN2 25
#define GPI_SYS_SPI0_CLK 26
#define GPI_SYS_SPI0_FSS 27
#define GPI_SYS_SPI0_RXD 28
#define GPI_SYS_JTAG_TCK 29
#define GPI_SYS_MCLK_EXT 30
#define GPI_SYS_I2SRX_BCLK 31
#define GPI_SYS_I2SRX_LRCK 32
#define GPI_SYS_I2STX1_BCLK 33
#define GPI_SYS_I2STX1_LRCK 34
#define GPI_SYS_TDM_CLK 35
#define GPI_SYS_TDM_RXD 36
#define GPI_SYS_TDM_SYNC 37
#define GPI_SYS_CAN1_RXD 38
#define GPI_SYS_I2C1_CLK 39
#define GPI_SYS_I2C1_DATA 40
#define GPI_SYS_SDIO1_CD 41
#define GPI_SYS_SDIO1_INT 42
#define GPI_SYS_SDIO1_WP 43
#define GPI_SYS_SDIO1_CMD 44
#define GPI_SYS_SDIO1_DATA0 45
#define GPI_SYS_SDIO1_DATA1 46
#define GPI_SYS_SDIO1_DATA2 47
#define GPI_SYS_SDIO1_DATA3 48
#define GPI_SYS_SDIO1_DATA4 49
#define GPI_SYS_SDIO1_DATA5 50
#define GPI_SYS_SDIO1_DATA6 51
#define GPI_SYS_SDIO1_DATA7 52
#define GPI_SYS_SDIO1_STRB 53
#define GPI_SYS_UART1_CTS 54
#define GPI_SYS_UART1_RX 55
#define GPI_SYS_SPI1_CLK 56
#define GPI_SYS_SPI1_FSS 57
#define GPI_SYS_SPI1_RXD 58
#define GPI_SYS_I2C2_CLK 59
#define GPI_SYS_I2C2_DATA 60
#define GPI_SYS_UART2_CTS 61
#define GPI_SYS_UART2_RX 62
#define GPI_SYS_SPI2_CLK 63
#define GPI_SYS_SPI2_FSS 64
#define GPI_SYS_SPI2_RXD 65
#define GPI_SYS_I2C3_CLK 66
#define GPI_SYS_I2C3_DATA 67
#define GPI_SYS_UART3_RX 68
#define GPI_SYS_SPI3_CLK 69
#define GPI_SYS_SPI3_FSS 70
#define GPI_SYS_SPI3_RXD 71
#define GPI_SYS_I2C4_CLK 72
#define GPI_SYS_I2C4_DATA 73
#define GPI_SYS_UART4_CTS 74
#define GPI_SYS_UART4_RX 75
#define GPI_SYS_SPI4_CLK 76
#define GPI_SYS_SPI4_FSS 77
#define GPI_SYS_SPI4_RXD 78
#define GPI_SYS_I2C5_CLK 79
#define GPI_SYS_I2C5_DATA 80
#define GPI_SYS_UART5_CTS 81
#define GPI_SYS_UART5_RX 82
#define GPI_SYS_SPI5_CLK 83
#define GPI_SYS_SPI5_FSS 84
#define GPI_SYS_SPI5_RXD 85
#define GPI_SYS_I2C6_CLK 86
#define GPI_SYS_I2C6_DATA 87
#define GPI_SYS_SPI6_CLK 88
#define GPI_SYS_SPI6_FSS 89
#define GPI_SYS_SPI6_RXD 90
/* aon_iomux gin */
#define GPI_AON_PMU_GPIO_WAKEUP_0 0
#define GPI_AON_PMU_GPIO_WAKEUP_1 1
#define GPI_AON_PMU_GPIO_WAKEUP_2 2
#define GPI_AON_PMU_GPIO_WAKEUP_3 3
#endif
File diff suppressed because it is too large Load Diff
@@ -38,7 +38,7 @@
#size-cells = <0x00>;
timebase-frequency = <0x989680>;
cpu@0 {
cpu0: cpu@0 {
phandle = <0x01>;
device_type = "cpu";
reg = <0x00>;
@@ -52,7 +52,7 @@
riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_zmmul_za64rs_zaamo_zalrsc_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_shcounterenw_shgatpa_shtvala_shvsatpa_shvstvala_shvstvecd_ssccptr_sscounterenw_sstc_sstvala_sstvecd_ssu64xl_svadu_svvptc";
mmu-type = "riscv,sv57";
interrupt-controller {
cpu0_intc: interrupt-controller {
#interrupt-cells = <0x01>;
interrupt-controller;
compatible = "riscv,cpu-intc";
@@ -61,11 +61,9 @@
};
cpu-map {
cluster0 {
core0 {
cpu = <0x01>;
cpu = <&cpu0>;
};
};
};
@@ -186,7 +184,8 @@
phandle = <0x03>;
riscv,ndev = <0x5f>;
reg = <0x00 0xc000000 0x00 0x600000>;
interrupts-extended = <0x02 0x0b 0x02 0x09>;
interrupts-extended = <&cpu0_intc 0x0b>,
<&cpu0_intc 0x09>;
interrupt-controller;
compatible = "sifive,plic-1.0.0", "riscv,plic0";
#address-cells = <0x00>;
@@ -194,7 +193,8 @@
};
clint@2000000 {
interrupts-extended = <0x02 0x03 0x02 0x07>;
interrupts-extended = <&cpu0_intc 0x03>,
<&cpu0_intc 0x07>;
reg = <0x00 0x2000000 0x00 0x10000>;
compatible = "sifive,clint0", "riscv,clint0";
};
+1
View File
@@ -35,6 +35,7 @@ ygg_driver_ahci = { path = "driver/block/ahci" }
ygg_driver_input = { path = "driver/input" }
ygg_driver_usb_xhci.path = "driver/usb/xhci"
ygg_driver_net_rtl81xx.path = "driver/net/rtl81xx"
ygg_driver_serial_8250.path = "driver/serial/uart8250"
memfs = { path = "driver/fs/memfs" }
ext2 = { path = "driver/fs/ext2" }
+9 -1
View File
@@ -16,7 +16,7 @@ use kernel_arch_interface::{
};
use libk_mm_interface::{
address::PhysicalAddress,
process::ProcessAddressSpaceManager,
process::{PageAttributeUpdate, ProcessAddressSpaceManager},
table::{MapAttributes, TableAllocator},
};
use yggdrasil_abi::{
@@ -164,6 +164,14 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
unimplemented!()
}
unsafe fn update_page_attributes(
&mut self,
_address: usize,
_update: &PageAttributeUpdate,
) -> Result<(), Error> {
unimplemented!()
}
fn translate(&self, _address: usize) -> Result<(PhysicalAddress, MapAttributes), Error> {
unimplemented!()
}
+24 -4
View File
@@ -1,3 +1,4 @@
// TODO baud rate configuration
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
@@ -16,7 +17,10 @@ use tock_registers::{
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
use yggdrasil_abi::{error::Error, io::TerminalOptions};
use yggdrasil_abi::{
error::Error,
io::{TerminalOptions, TerminalOutputOptions},
};
register_bitfields! {
u32,
@@ -89,14 +93,25 @@ impl Io {
}
impl TerminalOutput for Pl011Inner {
fn write(&self, byte: u8) -> Result<(), Error> {
self.io.lock().send(byte);
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error> {
let mut lock = self.io.lock();
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
lock.send(b'\r');
}
lock.send(b'\n');
Ok(())
}
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
fn write_multiple(
&self,
bytes: &[u8],
options: &TerminalOutputOptions,
) -> Result<usize, Error> {
let mut lock = self.io.lock();
for &byte in bytes {
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
lock.send(b'\r');
}
lock.send(byte);
}
Ok(bytes.len())
@@ -117,6 +132,11 @@ impl DebugSink for Pl011 {
self.inner.get().putc_to_output(byte)
}
fn puts(&self, s: &str) -> Result<(), Error> {
self.inner.get().write_to_output(s.as_bytes())?;
Ok(())
}
fn supports_control_sequences(&self) -> bool {
true
}
+18 -15
View File
@@ -68,10 +68,6 @@ pub struct Bcm2835AuxUart {
impl Regs {
fn write_byte(&self, byte: u8) -> Result<(), Error> {
if byte == b'\n' {
self.write_byte(b'\r').ok();
}
while !self
.AUX_MU_LSR_REG
.matches_all(AUX_MU_LSR_REG::TX_EMPTY::SET)
@@ -81,22 +77,29 @@ impl Regs {
self.AUX_MU_IO_REG.set(byte as u32);
Ok(())
}
fn write_bytes(&self, bytes: &[u8]) -> Result<(), Error> {
for &byte in bytes {
self.write_byte(byte)?;
}
Ok(())
}
}
impl TerminalOutput for Inner {
fn write(&self, byte: u8) -> Result<(), Error> {
self.regs.lock().write_byte(byte)
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error> {
let regs = self.regs.lock();
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
regs.write_byte(b'\r')?;
}
regs.write_byte(byte)
}
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
self.regs.lock().write_bytes(bytes)?;
fn write_multiple(
&self,
bytes: &[u8],
options: &TerminalOutputOptions,
) -> Result<usize, Error> {
let regs = self.regs.lock();
for &byte in bytes {
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
regs.write_byte(b'\r')?;
}
regs.write_byte(byte)?;
}
Ok(bytes.len())
}
}
+20
View File
@@ -57,6 +57,16 @@ const SYSCRG_GMAC0_GTXC: usize = 0x1BC / 4;
// uart
const SYSCRG_UART0_APB: usize = 0x244 / 4;
const SYSCRG_UART0_CORE: usize = 0x248 / 4;
const SYSCRG_UART1_APB: usize = 0x24C / 4;
const SYSCRG_UART1_CORE: usize = 0x250 / 4;
const SYSCRG_UART2_APB: usize = 0x254 / 4;
const SYSCRG_UART2_CORE: usize = 0x258 / 4;
const SYSCRG_UART3_APB: usize = 0x25C / 4;
const SYSCRG_UART3_CORE: usize = 0x260 / 4;
const SYSCRG_UART4_APB: usize = 0x264 / 4;
const SYSCRG_UART4_CORE: usize = 0x268 / 4;
const SYSCRG_UART5_APB: usize = 0x26C / 4;
const SYSCRG_UART5_CORE: usize = 0x270 / 4;
// jtag
const SYSCRG_JTAG_CERTIFICATION_TRNG: usize = 0x2F4 / 4;
const SYSCRG_CLOCK_COUNT: usize = SYSCRG_JTAG_CERTIFICATION_TRNG + 1;
@@ -226,6 +236,16 @@ const SYSCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
// uart
t[SYSCRG_UART0_APB] = Some(("clk_uart0_apb", Gate(SYSCRG_APB0)));
t[SYSCRG_UART0_CORE] = Some(("clk_uart0_core", Gate(SYSCRG_OSC)));
t[SYSCRG_UART1_APB] = Some(("clk_uart1_apb", Gate(SYSCRG_APB0)));
t[SYSCRG_UART1_CORE] = Some(("clk_uart1_core", Gate(SYSCRG_OSC)));
t[SYSCRG_UART2_APB] = Some(("clk_uart2_apb", Gate(SYSCRG_APB0)));
t[SYSCRG_UART2_CORE] = Some(("clk_uart2_core", Gate(SYSCRG_OSC)));
t[SYSCRG_UART3_APB] = Some(("clk_uart3_apb", Gate(SYSCRG_APB0)));
t[SYSCRG_UART3_CORE] = Some(("clk_uart3_core", GateDiv(10, SYSCRG_PERH_ROOT)));
t[SYSCRG_UART4_APB] = Some(("clk_uart4_apb", Gate(SYSCRG_APB0)));
t[SYSCRG_UART4_CORE] = Some(("clk_uart4_core", GateDiv(10, SYSCRG_PERH_ROOT)));
t[SYSCRG_UART5_APB] = Some(("clk_uart5_apb", Gate(SYSCRG_APB0)));
t[SYSCRG_UART5_CORE] = Some(("clk_uart5_core", GateDiv(10, SYSCRG_PERH_ROOT)));
t
};
+21
View File
@@ -0,0 +1,21 @@
[package]
name = "ygg_driver_serial_8250"
version = "0.1.0"
edition = "2024"
[dependencies]
device-tree.workspace = true
device-api.workspace = true
yggdrasil-abi.workspace = true
libk-mm.workspace = true
libk-util.workspace = true
libk.workspace = true
[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies]
kernel-arch-x86.workspace = true
[dev-dependencies]
kernel-arch-x86.workspace = true
[lints]
workspace = true
+180
View File
@@ -0,0 +1,180 @@
use alloc::{sync::Arc, vec::Vec};
use device_api::{
clock::{ClockHandle, Hertz, ResetHandle},
device::Device,
interrupt::{InterruptHandler, IrqHandle},
};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use libk::error::Error;
use libk_mm::{address::PhysicalAddress, device::RawDeviceMemoryMapping};
use crate::{Access, Config, PortConfig, Uart8250, Vendor};
pub struct Fdt8250Access {
mapping: RawDeviceMemoryMapping,
offset: usize,
shift: usize,
io_width: usize,
}
pub struct Fdt8250Config {
irq: IrqHandle,
ports: [Fdt8250PortConfig; 1],
}
pub struct Fdt8250PortConfig {
base: PhysicalAddress,
reg_offset: usize,
reg_shift: usize,
reg_io_width: usize,
resets: Vec<ResetHandle>,
clock_frequency: Option<Hertz>,
clk_baud: Option<ClockHandle>,
clk_apb: Option<ClockHandle>,
}
impl Access for Fdt8250Access {
type Config = Fdt8250Config;
unsafe fn map(config: &Fdt8250PortConfig) -> Result<Self, Error> {
let mapping = unsafe {
RawDeviceMemoryMapping::map(config.base.into_u64(), 0x1000, Default::default())
}?;
Ok(Self {
offset: config.reg_offset,
shift: config.reg_shift,
io_width: config.reg_io_width,
mapping,
})
}
fn read(&self, reg: u8) -> u8 {
let addr = ((reg as usize) << self.shift) + self.offset;
assert!(addr + self.io_width <= 0x1000);
let ptr = unsafe { self.mapping.as_non_null::<u8>().add(addr) };
match self.io_width {
4 => unsafe { ptr.cast::<u32>().read_volatile() as u8 },
1 => unsafe { ptr.cast::<u8>().read_volatile() },
_ => unimplemented!(),
}
}
fn write(&mut self, reg: u8, val: u8) {
let addr = ((reg as usize) << self.shift) + self.offset;
assert!(addr + self.io_width <= 0x1000);
let ptr = unsafe { self.mapping.as_non_null::<u8>().add(addr) };
match self.io_width {
4 => unsafe { ptr.cast::<u32>().write_volatile(val as u32) },
1 => unsafe { ptr.cast::<u8>().write_volatile(val) },
_ => unimplemented!(),
}
}
// fn read(&self, reg: usize) -> u32 {
// }
// fn write(&mut self, reg: usize, val: u32) {
// }
}
impl PortConfig for Fdt8250PortConfig {
fn input_clock_frequency(&self) -> Result<Hertz, Error> {
if let Some(clock_frequency) = self.clock_frequency {
Ok(clock_frequency)
} else if let Some(clk_baud) = self.clk_baud.as_ref() {
clk_baud.rate()
} else {
Err(Error::InvalidArgument)
}
}
fn deassert_resets(&self) -> Result<(), Error> {
for reset in self.resets.iter() {
reset.deassert()?;
}
Ok(())
}
fn enable_clocks(&self) -> Result<(), Error> {
if let Some(clk_apb) = self.clk_apb.as_ref() {
clk_apb.enable()?;
}
if let Some(clk_baud) = self.clk_baud.as_ref() {
clk_baud.enable()?;
}
Ok(())
}
}
impl Config for Fdt8250Config {
type Port = Fdt8250PortConfig;
fn ports(&self) -> &[Self::Port] {
&self.ports[..]
}
fn enable_interrupt(&self, handler: Arc<dyn InterruptHandler>) -> Result<(), Error> {
self.irq.register(handler)?;
self.irq.enable()?;
Ok(())
}
}
impl Fdt8250Config {
fn from_device_tree(node: &Arc<Node>, context: &mut ProbeContext) -> Option<(Self, Vendor)> {
let vendor = if node.is_compatible("snps,dw-apb-uart") {
Vendor::DwApbUart
} else if node.is_compatible("ns16550a") {
Vendor::Generic16550
} else {
Vendor::Generic8250
};
let base = node.map_base(context, 0)?;
let irq = node.interrupt(0)?;
let resets = node.resets().map(|r| r.collect()).unwrap_or_default();
let clock_frequency = node
.prop_usize("clock-frequency")
.map(|clk| Hertz(clk as _));
let clk_baud = node.named_clock("baudclk");
let clk_apb = node.named_clock("apb_pclk");
let reg_io_width = node.prop_usize("reg-io-width").unwrap_or(1);
let reg_offset = node.prop_usize("reg-offset").unwrap_or(0);
let reg_shift = node.prop_usize("reg-shift").unwrap_or(0);
Some((
Self {
irq,
ports: [Fdt8250PortConfig {
clk_apb,
clk_baud,
resets,
clock_frequency,
reg_io_width,
reg_offset,
reg_shift,
base,
}],
},
vendor,
))
}
}
device_tree_driver! {
compatible: [
"snps,dw-apb-uart",
"ns16550a",
],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let (config, vendor) = Fdt8250Config::from_device_tree(node, context)?;
let uart = Arc::new(Uart8250::<Fdt8250Access>::new(config, vendor));
Some(uart)
}
}
}
+81
View File
@@ -0,0 +1,81 @@
use alloc::sync::Arc;
use device_api::{
clock::Hertz,
interrupt::{InterruptHandler, Irq},
};
use kernel_arch_x86::intrinsics;
use libk::{device::external_interrupt_controller, error::Error};
use crate::{Access, Config, PortConfig};
pub struct Io8250Access {
io_base: u16,
}
pub struct Io8250Config {
ports: [Io8250PortConfig; 2],
irq: Irq,
}
pub struct Io8250PortConfig {
io_base: u16,
}
impl Io8250Config {
pub fn new(port_a: u16, port_b: u16, irq: Irq) -> Self {
Self {
ports: [
Io8250PortConfig { io_base: port_a },
Io8250PortConfig { io_base: port_b },
],
irq,
}
}
}
impl Access for Io8250Access {
type Config = Io8250Config;
unsafe fn map(config: &Io8250PortConfig) -> Result<Self, Error> {
Ok(Self {
io_base: config.io_base,
})
}
fn read(&self, reg: u8) -> u8 {
unsafe { intrinsics::inb(self.io_base + reg as u16) }
}
fn write(&mut self, reg: u8, val: u8) {
unsafe { intrinsics::outb(self.io_base + reg as u16, val) };
}
}
impl Config for Io8250Config {
type Port = Io8250PortConfig;
fn ports(&self) -> &[Self::Port] {
&self.ports
}
fn enable_interrupt(&self, handler: Arc<dyn InterruptHandler>) -> Result<(), Error> {
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq, Default::default(), handler)?;
intc.enable_irq(self.irq)?;
Ok(())
}
}
impl PortConfig for Io8250PortConfig {
fn input_clock_frequency(&self) -> Result<Hertz, Error> {
Ok(Hertz(115200 * 16))
}
fn enable_clocks(&self) -> Result<(), Error> {
Ok(())
}
fn deassert_resets(&self) -> Result<(), Error> {
Ok(())
}
}
+120
View File
@@ -0,0 +1,120 @@
#![no_std]
use core::iter;
use alloc::{sync::Arc, vec::Vec};
use device_api::{
clock::Hertz,
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqVector},
};
use libk::error::Error;
use libk_util::OneTimeInit;
use crate::port::Port8250;
extern crate alloc;
#[cfg(any(rust_analyzer, target_arch = "aarch64", target_arch = "riscv64"))]
pub mod fdt;
#[cfg(any(rust_analyzer, target_arch = "x86_64", target_arch = "x86"))]
pub mod io;
pub mod port;
pub trait Config: Sync + Send {
type Port: PortConfig;
fn ports(&self) -> &[Self::Port];
fn enable_interrupt(&self, handler: Arc<dyn InterruptHandler>) -> Result<(), Error>;
}
pub trait PortConfig: Sync + Send {
fn input_clock_frequency(&self) -> Result<Hertz, Error>;
fn enable_clocks(&self) -> Result<(), Error>;
fn deassert_resets(&self) -> Result<(), Error>;
}
pub trait Access: Sized + Send + 'static {
type Config: Config;
unsafe fn map(config: &<Self::Config as Config>::Port) -> Result<Self, Error>;
fn read(&self, reg: u8) -> u8;
fn write(&mut self, reg: u8, val: u8);
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Vendor {
DwApbUart,
Generic8250,
Generic16550,
}
pub struct Uart8250<A: Access> {
config: A::Config,
vendor: Vendor,
ports: Vec<Arc<Port8250<A>>>,
}
impl<A: Access> Uart8250<A> {
pub fn new(config: A::Config, vendor: Vendor) -> Self {
let ports = config
.ports()
.iter()
.map(|_| {
Arc::new(Port8250 {
vendor,
inner: OneTimeInit::new(),
})
})
.collect();
Self {
config,
vendor,
ports,
}
}
pub unsafe fn init_inner(self: &Arc<Self>) -> Result<(), Error> {
let ports = self.ports.iter();
let port_configs = self.config.ports().iter();
for (port, config) in iter::zip(ports, port_configs) {
port.clone().init(config)?;
}
Ok(())
}
}
impl<A: Access> Device for Uart8250<A> {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
unsafe { self.init_inner() }
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.config.enable_interrupt(self.clone())?;
for port in self.ports.iter() {
port.enable_irq();
}
Ok(())
}
fn display_name(&self) -> &str {
match self.vendor {
Vendor::DwApbUart => "Synopsys DesignWare 16550 UART",
Vendor::Generic16550 => "16550 UART",
Vendor::Generic8250 => "8250 UART",
}
}
}
impl<A: Access> InterruptHandler for Uart8250<A> {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
for port in self.ports.iter() {
if port.handle_irq() {
return true;
}
}
false
}
}
+257
View File
@@ -0,0 +1,257 @@
use core::ops::{Deref, DerefMut};
use alloc::sync::Arc;
use device_api::clock::Hertz;
use libk::{
debug::{self, DebugSink},
device::manager::DEVICE_REGISTRY,
error::Error,
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use yggdrasil_abi::io::{TerminalOptions, TerminalOutputOptions};
use crate::{Access, Config, PortConfig, Vendor};
const REG_RBR: u8 = 0;
const REG_THR: u8 = 0;
const REG_DLL: u8 = 0;
const REG_IER: u8 = 1;
const REG_DLH: u8 = 1;
const REG_IIR: u8 = 2;
const REG_FCR: u8 = 2;
const REG_LCR: u8 = 3;
const REG_MCR: u8 = 4;
const REG_LSR: u8 = 5;
// Vendor-specific
const DW_REG_USR: u8 = 31;
const DW_REG_SRR: u8 = 34;
const DW_REG_HTX: u8 = 41;
/// Received Data available interrupt
const IER_RXDE: u8 = 1 << 0;
/// Received Data available
const IIR_RXDA: u8 = 0b100;
const IIR_MASK: u8 = 0x7;
const FCR_FIFO_ENABLE: u8 = 1 << 0;
const FCR_RX_FIFO_RESET: u8 = 1 << 1;
const FCR_TX_FIFO_RESET: u8 = 1 << 2;
const LCR_BITS_8: u8 = 0x3;
const LCR_DLAB: u8 = 1 << 7;
const MCR_DTR: u8 = 1 << 0;
const MCR_RTS: u8 = 1 << 1;
const LSR_TEMT: u8 = 1 << 6;
pub struct Port8250<A: Access> {
pub(crate) vendor: Vendor,
pub(crate) inner: OneTimeInit<Arc<Terminal<Inner<A>>>>,
}
struct PortRegs<A: Access> {
regs: A,
baud_rate: u32,
input_clock: Hertz,
}
pub(crate) struct Inner<A: Access> {
regs: IrqSafeSpinlock<PortRegs<A>>,
}
impl<A: Access> Port8250<A> {
pub(crate) fn init(self: Arc<Self>, config: &<A::Config as Config>::Port) -> Result<(), Error> {
let _guard = debug::MuteGuard::acquire();
// Deassert reset signal and enable clocks
config.enable_clocks()?;
config.deassert_resets()?;
let input_clock = config.input_clock_frequency()?;
let mut regs = PortRegs {
regs: unsafe { A::map(config) }?,
baud_rate: 0,
input_clock,
};
regs.init(self.vendor, 115200)?;
let input = TerminalInput::with_capacity(64)?;
let output = Inner {
regs: IrqSafeSpinlock::new(regs),
};
let terminal = self.inner.init(Arc::new(Terminal::from_parts(
TerminalOptions::const_default(),
input,
output,
)));
DEVICE_REGISTRY
.serial_terminal
.register(terminal.clone(), Some(self.clone()))
.ok();
Ok(())
}
pub(crate) fn enable_irq(&self) {
let mut regs = self.inner.get().output().regs.lock();
regs.write(REG_IER, IER_RXDE);
}
pub(crate) fn handle_irq(&self) -> bool {
let inner = self.inner.get();
let byte = {
let regs = inner.output().regs.lock();
let iir = regs.read(REG_IIR) & IIR_MASK;
if iir == IIR_RXDA {
Some(regs.read(REG_RBR) as u8)
} else {
None
}
};
if let Some(byte) = byte {
inner.write_to_input(byte);
true
} else {
false
}
}
}
impl<A: Access> DebugSink for Port8250<A> {
fn putc(&self, c: u8) -> Result<(), Error> {
self.inner.get().putc_to_output(c)
}
fn supports_control_sequences(&self) -> bool {
true
}
}
impl<A: Access> TerminalOutput for Inner<A> {
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error> {
let mut regs = self.regs.lock();
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
regs.serial_out(b'\r')?;
}
regs.serial_out(byte)
}
fn write_multiple(
&self,
bytes: &[u8],
options: &TerminalOutputOptions,
) -> Result<usize, Error> {
let mut regs = self.regs.lock();
for &byte in bytes {
if byte == b'\n' && options.contains(TerminalOutputOptions::NL_TO_CRNL) {
regs.serial_out(b'\r')?;
}
regs.serial_out(byte)?;
}
Ok(bytes.len())
}
fn set_baud_rate(&self, baud: u32) -> Result<(), Error> {
let mut regs = self.regs.lock();
regs.set_baud_rate(baud)
}
fn baud_rate(&self) -> u32 {
let regs = self.regs.lock();
regs.baud_rate
}
}
impl<A: Access> PortRegs<A> {
fn init(&mut self, vendor: Vendor, baud_rate: u32) -> Result<(), Error> {
if vendor == Vendor::DwApbUart {
self.write(DW_REG_SRR, 1);
delay();
self.write(DW_REG_HTX, 0);
delay();
// wait while DW USR.BUSY == 1
while self.read(DW_REG_USR) & (1 << 0) != 0 {
core::hint::spin_loop();
}
}
self.set_baud_rate(baud_rate)
}
fn serial_out(&mut self, byte: u8) -> Result<(), Error> {
let mut timeout = 1000000;
while timeout > 0 && self.read(REG_LSR) & LSR_TEMT == 0 {
timeout -= 1;
}
if timeout == 0 {
return Err(Error::TimedOut);
}
self.write(REG_THR, byte);
Ok(())
}
fn set_baud_rate(&mut self, baud_rate: u32) -> Result<(), Error> {
// TODO check that the divisor actually fits
self.baud_rate = baud_rate;
let divisor = (self.input_clock.0 / (baud_rate as u64 * 16)) as u32;
// Disable interrupts, clear FCR/MCR
self.write(REG_IER, 0x00);
self.write(REG_MCR, 0x00);
self.write(REG_FCR, 0x00);
// Program divisor
// DLAB=1
let lcr = self.read(REG_LCR);
self.write(REG_LCR, lcr | LCR_DLAB);
self.write(REG_DLH, ((divisor >> 8) & 0xFF) as u8);
self.write(REG_DLL, (divisor & 0xFF) as u8);
delay();
let lcr = self.read(REG_LCR);
self.write(REG_LCR, lcr & !LCR_DLAB);
delay();
// 8n1 setting
let lcr = self.read(REG_LCR);
self.write(REG_LCR, lcr | LCR_BITS_8);
delay();
// DTR+RTS
self.write(REG_MCR, MCR_DTR | MCR_RTS);
// Enable and drain FIFO
self.write(REG_FCR, FCR_FIFO_ENABLE);
delay();
let fcr = self.read(REG_FCR);
self.write(REG_FCR, fcr | FCR_RX_FIFO_RESET | FCR_TX_FIFO_RESET);
delay();
// TODO flush Rx
Ok(())
}
}
impl<A: Access> Deref for PortRegs<A> {
type Target = A;
fn deref(&self) -> &Self::Target {
&self.regs
}
}
impl<A: Access> DerefMut for PortRegs<A> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.regs
}
}
fn delay() {
for _ in 0..10000 {
core::hint::spin_loop();
}
}
+12 -12
View File
@@ -105,18 +105,18 @@ impl Node {
.as_str_list()
.find_map(|c| drivers.iter().find(|d| d.matches(c)));
if libk::config::get().device_tree.log_missing && driver.is_none() {
// FIXME don't spam virtio missing stuff
if !name.is_some_and(|n| n.starts_with("virtio_mmio")) {
for (i, compatible) in compatible.as_str_list().enumerate() {
if i == 0 {
log::warn!("No driver for {name:?} ({compatible:?})");
} else {
log::warn!(" also {compatible:?}");
}
}
}
}
// if libk::config::get().device_tree.log_missing && driver.is_none() {
// // FIXME don't spam virtio missing stuff
// if !name.is_some_and(|n| n.starts_with("virtio_mmio")) {
// for (i, compatible) in compatible.as_str_list().enumerate() {
// if i == 0 {
// log::warn!("No driver for {name:?} ({compatible:?})");
// } else {
// log::warn!(" also {compatible:?}");
// }
// }
// }
// }
let driver = driver?;
// Initialize default pinctrl before probing
+7 -2
View File
@@ -8,7 +8,11 @@ use libk_util::{
StaticVector,
sync::{IrqSafeSpinlock, spin_rwlock::IrqSafeRwLock},
};
use yggdrasil_abi::{error::Error, io::TerminalSize, primitive_enum};
use yggdrasil_abi::{
error::Error,
io::{TerminalOutputOptions, TerminalSize},
primitive_enum,
};
use crate::{task::runtime, vfs::TerminalOutput};
@@ -520,7 +524,8 @@ impl TerminalOutput for ConsoleWrapper {
TerminalSize { rows, columns }
}
fn write(&self, byte: u8) -> Result<(), Error> {
fn write(&self, byte: u8, _options: &TerminalOutputOptions) -> Result<(), Error> {
// TODO handle options
self.0.write_char(byte);
Ok(())
}
+8 -3
View File
@@ -11,7 +11,7 @@ use async_trait::async_trait;
use libk_util::{ring::BlockingRingQueue, sync::spin_rwlock::IrqSafeRwLock};
use yggdrasil_abi::{
error::Error,
io::{TerminalOptions, TerminalSize},
io::{TerminalOptions, TerminalOutputOptions, TerminalSize},
};
use super::{
@@ -28,11 +28,16 @@ struct PtyOutput {
}
impl TerminalOutput for PtyOutput {
fn write(&self, byte: u8) -> Result<(), Error> {
// TODO options
fn write(&self, byte: u8, _options: &TerminalOutputOptions) -> Result<(), Error> {
block!(self.ring.write(byte).await)
}
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
fn write_multiple(
&self,
bytes: &[u8],
_options: &TerminalOutputOptions,
) -> Result<usize, Error> {
block!(self.ring.write_all(bytes).await)?;
Ok(bytes.len())
}
+19 -12
View File
@@ -41,7 +41,7 @@ pub struct TerminalInput {
// Program -> screen, PTY master, terminal, etc.
pub trait TerminalOutput: Sync + Send {
fn write(&self, byte: u8) -> Result<(), Error>;
fn write(&self, byte: u8, options: &TerminalOutputOptions) -> Result<(), Error>;
fn notify_readers(&self) {}
@@ -56,10 +56,14 @@ pub trait TerminalOutput: Sync + Send {
Err(Error::InvalidOperation)
}
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
fn write_multiple(
&self,
bytes: &[u8],
options: &TerminalOutputOptions,
) -> Result<usize, Error> {
let mut written = 0;
for &byte in bytes {
self.write(byte)?;
self.write(byte, options)?;
written += 1;
}
Ok(written)
@@ -126,12 +130,14 @@ impl<O: TerminalOutput> Terminal<O> {
}
pub fn putc_to_output(&self, byte: u8) -> Result<(), Error> {
self.output.write(byte)
let options = self.config.read().output;
self.output.write(byte, &options)
}
pub fn write_to_output(&self, buffer: &[u8]) -> Result<usize, Error> {
let options = self.config.read().output;
// TODO handle options
self.output.write_multiple(buffer)
self.output.write_multiple(buffer, &options)
}
pub fn write_to_input(&self, mut byte: u8) {
@@ -151,7 +157,9 @@ impl<O: TerminalOutput> Terminal<O> {
buffer.erase_pending() && config.line.contains(TerminalLineOptions::ECHO_ERASE);
if echo {
self.output.write_multiple(b"\x1B[D \x1B[D").ok();
self.output
.write_multiple(b"\x1B[D \x1B[D", &config.output)
.ok();
}
return;
@@ -160,17 +168,16 @@ impl<O: TerminalOutput> Terminal<O> {
if byte == b'\n' {
// TODO NL_TO_CRNL
if config.is_echo_newline() {
if config.output.contains(TerminalOutputOptions::NL_TO_CRNL) {
self.output.write(b'\r').ok();
}
self.output.write(byte).ok();
self.output.write(byte, &config.output).ok();
}
} else if byte.is_ascii_control() {
if config.line.contains(TerminalLineOptions::ECHO) {
self.output.write_multiple(&[b'^', byte + 0x40]).ok();
self.output
.write_multiple(&[b'^', byte + 0x40], &config.output)
.ok();
}
} else if config.line.contains(TerminalLineOptions::ECHO) {
self.output.write(byte).ok();
self.output.write(byte, &config.output).ok();
}
if byte == config.chars.interrupt {
+5
View File
@@ -168,6 +168,11 @@ impl Riscv64 {
if is_bsp {
call_init_array();
unsafe extern "C" {
static __kernel_start: u8;
}
log::info!("Boot address: {:#x}", (&raw const __kernel_start).addr());
atomic::compiler_fence(Ordering::SeqCst);
libk::debug::init();
+28 -11
View File
@@ -20,8 +20,12 @@ use libk_mm::{
phys::{self, PhysicalMemoryRegion},
table::EntryLevelExt,
};
use peripherals::{i8253::I8253, ps2::PS2Controller, rtc::Rtc, serial::ComPort};
use peripherals::{i8253::I8253, ps2::PS2Controller, rtc::Rtc};
use ygg_driver_pci::PciBusManager;
use ygg_driver_serial_8250::{
Uart8250,
io::{Io8250Access, Io8250Config},
};
use crate::fs::{INITRD_DATA, Initrd};
@@ -43,8 +47,8 @@ struct ProbeClockSource {
}
pub struct EarlyPlatformDevices {
pub com1_3: Arc<ComPort>,
com1_3: Arc<Uart8250<Io8250Access>>,
com2_4: Arc<Uart8250<Io8250Access>>,
clock_sources: Vec<ProbeClockSource>,
}
@@ -72,12 +76,18 @@ pub fn init_platform_early(cmdline: &str) -> Result<EarlyPlatformDevices, Error>
// Initialize async executor queue
runtime::init_task_queue();
let com1_3 = ComPort::setup(
dummy_init_context(),
0x3F8,
0x3E8,
Irq::External(ISA_IRQ_OFFSET + 4),
)?;
let com1_3_config = Io8250Config::new(0x3F8, 0x3E8, Irq::External(ISA_IRQ_OFFSET + 4));
let com2_4_config = Io8250Config::new(0x2F8, 0x2E8, Irq::External(ISA_IRQ_OFFSET + 3));
let com1_3 = Arc::new(Uart8250::<Io8250Access>::new(
com1_3_config,
ygg_driver_serial_8250::Vendor::Generic8250,
));
unsafe { com1_3.init_inner() }?;
let com2_4 = Arc::new(Uart8250::<Io8250Access>::new(
com2_4_config,
ygg_driver_serial_8250::Vendor::Generic8250,
));
// let i8259 = I8259::setup().expect("Could not initialize i8259 PIC");
// disable_i8259();
@@ -85,6 +95,7 @@ pub fn init_platform_early(cmdline: &str) -> Result<EarlyPlatformDevices, Error>
Ok(EarlyPlatformDevices {
com1_3,
com2_4,
clock_sources: Vec::new(),
})
}
@@ -116,8 +127,14 @@ pub fn init_platform_devices(early: EarlyPlatformDevices) {
if let Err(error) = Rtc::setup() {
log::error!("RTC init error: {error:?}");
}
if let Err(error) = unsafe { early.com1_3.port_a().clone().init_irq() } {
log::error!("COM port IRQ init error: {error:?}");
if let Err(error) = unsafe { early.com2_4.init_inner() } {
log::error!("COM port 2/4 init error: {error:?}");
}
if let Err(error) = unsafe { early.com1_3.init_irq() } {
log::error!("COM port 1/3 IRQ init error: {error:?}");
}
if let Err(error) = unsafe { early.com2_4.init_irq() } {
log::error!("COM port 2/4 IRQ init error: {error:?}");
}
if let Err(error) = PciBusManager::probe_bus_devices() {
-1
View File
@@ -1,7 +1,6 @@
pub mod i8253;
pub mod ps2;
pub mod rtc;
pub mod serial;
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
pub mod hpet;
-218
View File
@@ -1,218 +0,0 @@
//! Driver for x86 COM ports
use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, Irq, IrqVector},
};
use kernel_arch_x86::intrinsics::{IoPort, IoPortAccess};
use libk::{
debug::DebugSink,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_util::sync::IrqSafeSpinlock;
// Single port
struct Regs {
dr: IoPort<u8>,
lsr: IoPort<u8>,
lcr: IoPort<u8>,
ier: IoPort<u8>,
isr: IoPort<u8>,
baud_rate: u32,
}
struct PortInner {
regs: IrqSafeSpinlock<Regs>,
}
/// Single port of the COM port pair
pub struct Port {
terminal: Arc<Terminal<PortInner>>,
irq: Irq,
}
/// COM port pair
#[allow(unused)]
pub struct ComPort {
port_a: Arc<Port>,
port_b: Arc<Port>,
}
impl Regs {
fn write(&mut self, byte: u8) -> Result<(), Error> {
while self.lsr.read() & Port::LSR_THRE == 0 {
core::hint::spin_loop();
}
self.dr.write(byte);
Ok(())
}
}
impl PortInner {
fn handle_irq(&self) -> Option<u8> {
let (status, value) = {
let inner = self.regs.lock();
let status = inner.isr.read();
let value = inner.dr.read();
(status, value)
};
if status & Port::ISR_IRQ_MASK != 0 {
Some(value)
} else {
None
}
}
}
impl TerminalOutput for PortInner {
fn write(&self, byte: u8) -> Result<(), Error> {
self.regs.lock().write(byte)
}
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
let mut regs = self.regs.lock();
for &b in bytes {
regs.write(b)?;
}
Ok(bytes.len())
}
fn baud_rate(&self) -> u32 {
self.regs.lock().baud_rate
}
fn set_baud_rate(&self, baud: u32) -> Result<(), Error> {
if baud > 115200 {
log::warn!("Tried to set baud rate for COM port beyond 115200: {baud}");
return Err(Error::InvalidArgument);
}
let div = 115200 / baud;
let mut regs = self.regs.lock();
regs.lcr.write(regs.lcr.read() | (1 << 7));
regs.dr.write(div as u8);
regs.ier.write((div >> 8) as u8);
regs.lcr.write(regs.lcr.read() & !(1 << 7));
regs.baud_rate = baud;
Ok(())
}
}
impl DebugSink for Port {
fn putc(&self, c: u8) -> Result<(), Error> {
self.terminal.putc_to_output(c).ok();
Ok(())
}
fn puts(&self, s: &str) -> Result<(), Error> {
self.terminal.write_to_output(s.as_bytes()).ok();
Ok(())
}
fn supports_control_sequences(&self) -> bool {
true
}
}
impl InterruptHandler for Port {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let inner = self.terminal.output();
if let Some(byte) = inner.handle_irq() {
self.terminal.write_to_input(byte);
true
} else {
false
}
}
}
impl Device for Port {
fn display_name(&self) -> &'static str {
"COM port"
}
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
self.terminal.output().set_baud_rate(115200)?;
DEVICE_REGISTRY
.serial_terminal
.register(self.terminal.clone(), Some(self.clone()))
.ok();
Ok(())
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
let intc = external_interrupt_controller()?;
// TODO check that the same IRQ is not bound already for another port
intc.register_irq(self.irq, Default::default(), self.clone())?;
intc.enable_irq(self.irq)?;
let regs = self.terminal.output().regs.lock();
regs.ier.modify(|v| v | Self::IER_RXDA);
Ok(())
}
}
impl Port {
const LSR_THRE: u8 = 1 << 5;
const IER_RXDA: u8 = 1 << 0;
const ISR_IRQ_MASK: u8 = 3 << 1;
fn new(base: u16, irq: Irq) -> Result<Self, Error> {
let input = TerminalInput::with_capacity(64)?;
let output = PortInner {
regs: IrqSafeSpinlock::new(Regs {
dr: IoPort::new(base),
lsr: IoPort::new(base + 5),
ier: IoPort::new(base + 1),
isr: IoPort::new(base + 2),
lcr: IoPort::new(base + 3),
baud_rate: 0,
}),
};
let terminal = Terminal::from_parts(TerminalOptions::const_default(), input, output);
Ok(Self {
terminal: Arc::new(terminal),
irq,
})
}
}
impl ComPort {
/// Constructs a COM port pair
fn new(port_a: u16, port_b: u16, irq: Irq) -> Result<Self, Error> {
Ok(Self {
port_a: Arc::new(Port::new(port_a, irq)?),
port_b: Arc::new(Port::new(port_b, irq)?),
})
}
pub fn setup(
cx: DeviceInitContext,
port_a: u16,
port_b: u16,
irq: Irq,
) -> Result<Arc<Self>, Error> {
let this = Arc::new(Self::new(port_a, port_b, irq)?);
unsafe { this.port_a().clone().init(cx) }?;
Ok(this)
}
/// Returns a reference to the A port of this COM pair
pub fn port_a(&self) -> &Arc<Port> {
&self.port_a
}
}
-1
View File
@@ -7,7 +7,6 @@ pub mod bus;
pub mod clock;
pub mod display;
pub mod power;
pub mod serial;
// pub mod timer;
#[cfg(any(rust_analyzer, not(target_arch = "x86_64")))]
-6
View File
@@ -1,6 +0,0 @@
//! Serial device interfaces
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
pub mod ns16550a;
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
pub mod snps_dw_apb_uart;
-204
View File
@@ -1,204 +0,0 @@
//! 16550-style UART device driver
use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use libk::{
debug::DebugSink,
device::manager::DEVICE_REGISTRY,
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
register_bitfields!(
u8,
IER [
/// Received data ready
RDR OFFSET(0) NUMBITS(1) [],
/// Trasmitter holding register empty
THRE OFFSET(1) NUMBITS(1) [],
/// Receiver line status
RLS OFFSET(2) NUMBITS(1) [],
/// Modem status
MS OFFSET(3) NUMBITS(1) [],
],
LSR [
/// Data ready indicator
DR OFFSET(0) NUMBITS(1) [],
/// Transmitter FIFO empty
TFE OFFSET(5) NUMBITS(1) [],
],
LCR [
BITS OFFSET(0) NUMBITS(2) [
Bits8 = 3
],
STOPBITS OFFSET(2) NUMBITS(1) [],
PARITY OFFSET(3) NUMBITS(1) [],
PARITY_EVEN OFFSET(4) NUMBITS(1) [],
PARITY_STICK OFFSET(5) NUMBITS(1) [],
BREAK OFFSET(6) NUMBITS(1) [],
DLAB OFFSET(7) NUMBITS(1) [],
]
);
register_structs! {
#[allow(non_snake_case)]
Regs {
// Read: receive buffer, write: transmit buffer
(0x00 => DR: ReadWrite<u8>),
(0x01 => IER: ReadWrite<u8, IER::Register>),
// Read: interrupt idenditication, write: FIFO control
(0x02 => FCR: ReadWrite<u8>),
(0x03 => LCR: ReadWrite<u8, LCR::Register>),
(0x04 => MCR: WriteOnly<u8>),
(0x05 => LSR: ReadOnly<u8, LSR::Register>),
(0x06 => MSR: ReadOnly<u8>),
(0x07 => _0),
(0x08 => @END),
}
}
struct Io {
regs: DeviceMemoryIo<'static, Regs>,
}
struct Inner {
io: IrqSafeSpinlock<Io>,
}
/// ns16550a-style UART driver
pub struct Ns16550a {
inner: OneTimeInit<Arc<Terminal<Inner>>>,
base: PhysicalAddress,
irq: IrqHandle,
}
impl Io {
fn init(&mut self) {
self.regs.LCR.write(
LCR::BITS::Bits8 + LCR::BREAK::CLEAR + LCR::STOPBITS::CLEAR + LCR::PARITY::CLEAR,
);
self.regs.IER.set(0);
}
fn send(&mut self, byte: u8) {
while self.regs.LSR.matches_all(LSR::TFE::CLEAR) {
core::hint::spin_loop();
}
self.regs.DR.set(byte);
}
fn handle_irq(&self) -> Option<u8> {
let status = self.regs.FCR.get() & 0xF;
if status == 0b1100 || status == 0b0100 {
Some(self.regs.DR.get())
} else {
None
}
}
}
impl Device for Ns16550a {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
log::info!("Init ns16550a @ {:#x}", self.base);
let mut io = Io {
regs: DeviceMemoryIo::map(self.base, Default::default())?,
};
io.init();
let input = TerminalInput::with_capacity(64)?;
let output = Inner {
io: IrqSafeSpinlock::new(io),
};
let terminal = self.inner.init(Arc::new(Terminal::from_parts(
TerminalOptions::const_default(),
input,
output,
)));
DEVICE_REGISTRY
.serial_terminal
.register(terminal.clone(), Some(self.clone()))
.ok();
Ok(())
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
let io = self.inner.get().output().io.lock();
io.regs.IER.modify(IER::RDR::SET);
Ok(())
}
fn display_name(&self) -> &str {
"ns16550a UART"
}
}
impl InterruptHandler for Ns16550a {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let inner = self.inner.get();
let output = inner.output();
let byte = output.io.lock().handle_irq();
if let Some(byte) = byte {
inner.write_to_input(byte);
true
} else {
false
}
}
}
impl TerminalOutput for Inner {
fn write(&self, byte: u8) -> Result<(), Error> {
self.io.lock().send(byte);
Ok(())
}
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
let mut lock = self.io.lock();
for &byte in bytes {
lock.send(byte);
}
Ok(bytes.len())
}
}
impl DebugSink for Ns16550a {
fn putc(&self, c: u8) -> Result<(), Error> {
self.inner.get().putc_to_output(c)
}
fn supports_control_sequences(&self) -> bool {
true
}
}
device_tree_driver!(
compatible: ["ns16550a"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
log::debug!("ns16550a base = {base:#x}");
let irq = node.interrupt(0)?;
Some(Arc::new(Ns16550a {
base,
irq,
inner: OneTimeInit::new(),
}))
}
}
);
@@ -1,304 +0,0 @@
//! Synopsys DesignWare 8250 driver
use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
clock::{ClockHandle, Hertz, ResetHandle},
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use libk::{
debug::{self, DebugSink},
device::manager::DEVICE_REGISTRY,
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
register_bitfields! {
u32,
LCR [
DLAB OFFSET(7) NUMBITS(1) [],
DLS OFFSET(0) NUMBITS(2) [
DL8b = 0b11,
],
],
IER [
PTIME OFFSET(7) NUMBITS(1) [],
EDSSI OFFSET(3) NUMBITS(1) [],
ELSI OFFSET(2) NUMBITS(1) [],
// Transmit buffer available
ETBEI OFFSET(1) NUMBITS(1) [],
// Receive data available
ERBFI OFFSET(0) NUMBITS(1) [],
],
LSR [
// Data ready bit
DR OFFSET(0) NUMBITS(1) [],
// Transmitter holding register empty
THRE OFFSET(5) NUMBITS(1) [],
],
USR [
BUSY OFFSET(0) NUMBITS(1) [],
]
}
register_structs! {
#[allow(non_snake_case)]
Regs {
// DLAB=0, Write: transmitter holding register/Read: receiver buffer register
// DLAB=1, Read/Write: divisor latch low
(0x000 => DR: ReadWrite<u32>),
// DLAB=0: Interrupt enable register
// DLAB=1: Divisor latch high
(0x004 => IER: ReadWrite<u32, IER::Register>),
// Read: interrupt identification register/Write: frame control register
(0x008 => IIR: ReadWrite<u32>),
// Line control register
(0x00C => LCR: ReadWrite<u32, LCR::Register>),
// Modem control register
(0x010 => MCR: ReadWrite<u32>),
// Line status register
(0x014 => LSR: ReadOnly<u32, LSR::Register>),
// Modem status register
(0x018 => MSR: ReadOnly<u32>),
// Scratchpad
(0x01C => SCR: ReadWrite<u32>),
// Low-power divisor latch low
(0x020 => LPDLL: ReadWrite<u32>),
// Low-power divisor latch high
(0x024 => LPDLH: ReadWrite<u32>),
(0x028 => _0),
// Shadow receive/transmit buffer
(0x030 => SDR: [ReadWrite<u32>; 16]),
(0x070 => FAR: ReadWrite<u32>),
(0x074 => TFR: ReadOnly<u32>),
(0x078 => RFW: WriteOnly<u32>),
(0x07C => USR: ReadOnly<u32, USR::Register>),
(0x080 => TFL: ReadOnly<u32>),
(0x084 => RFL: ReadOnly<u32>),
(0x088 => SRR: WriteOnly<u32>),
(0x08C => SRTS: ReadWrite<u32>),
(0x090 => SBCR: ReadWrite<u32>),
(0x094 => SDMAM: ReadWrite<u32>),
(0x098 => SFE: ReadWrite<u32>),
(0x09C => SRT: ReadWrite<u32>),
(0x0A0 => STET: ReadWrite<u32>),
(0x0A4 => HTX: ReadWrite<u32>),
(0x0A8 => DMASA: WriteOnly<u32>),
(0x0AC => _1),
(0x0F4 => CPR: ReadOnly<u32>),
(0x0F8 => UCV: ReadOnly<u32>),
(0x0FC => CTR: ReadOnly<u32>),
(0x100 => @END),
}
}
struct Io {
regs: DeviceMemoryIo<'static, Regs>,
}
struct Inner {
io: IrqSafeSpinlock<Io>,
}
/// Synopsys DesignWare 8250 UART
pub struct DwUart {
base: PhysicalAddress,
irq: IrqHandle,
clk_baud: ClockHandle,
#[allow(unused)]
clk_apb: Option<ClockHandle>,
rst: Option<ResetHandle>,
inner: OneTimeInit<Arc<Terminal<Inner>>>,
}
impl Io {
fn send(&mut self, byte: u8) {
// TODO
if byte == b'\n' {
self.send(b'\r');
}
while !self.regs.LSR.matches_all(LSR::THRE::SET) {
core::hint::spin_loop();
}
self.regs.DR.set(byte as u32);
}
fn init(&mut self, baud_clock: Hertz, baud_rate: u64) {
let divisor = (baud_clock.0 / (baud_rate * 16)) as u32;
self.wait_busy();
self.regs.IER.set(0);
for _ in 0..100 {
let _ = self.regs.LSR.get();
}
for _ in 0..100 {
let _ = self.regs.DR.get();
}
self.wait_busy();
self.regs.LCR.write(LCR::DLAB::SET);
self.wait_busy();
self.regs.DR.set(divisor & 0xFF);
self.regs.IER.set((divisor >> 8) & 0xFF);
self.wait_busy();
self.regs.LCR.write(LCR::DLS::DL8b);
self.wait_busy();
self.regs.IIR.set(0x01);
self.wait_busy();
self.regs.MCR.set(0x00);
let _ = self.regs.LSR.get();
for _ in 0..100 {
let _ = self.regs.DR.get();
}
self.regs.SCR.set(0x00);
}
fn handle_irq(&mut self) -> Option<u8> {
let status = self.regs.IIR.get();
if status & 0xF == 4 {
Some(self.regs.DR.get() as u8)
} else {
None
}
}
fn wait_busy(&self) {
for _ in 0..100000 {
core::hint::spin_loop();
}
let mut timeout = 1000000;
while timeout > 0 && self.regs.USR.matches_all(USR::BUSY::SET) {
core::hint::spin_loop();
timeout -= 1;
}
}
}
impl InterruptHandler for DwUart {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let inner = self.inner.get();
let output = inner.output();
let byte = output.io.lock().handle_irq();
if let Some(byte) = byte {
inner.write_to_input(byte);
true
} else {
false
}
}
}
impl Device for DwUart {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
let baud_rate = 115200;
let clk_baud_rate = self.clk_baud.rate()?;
// Prevent firmware (SBI in riscv64) from printing to UART while it's being
// reset/initialized
let guard = debug::MuteGuard::acquire();
let regs = DeviceMemoryIo::<Regs>::map(self.base, Default::default())?;
let mut io = Io { regs };
if let Some(reset) = self.rst.as_ref() {
reset.assert_for_cycles(100000)?;
}
io.init(clk_baud_rate, baud_rate);
io.send(b'\r');
io.send(b'\n');
drop(guard);
let input = TerminalInput::with_capacity(64)?;
let output = Inner {
io: IrqSafeSpinlock::new(io),
};
let terminal = self.inner.init(Arc::new(Terminal::from_parts(
TerminalOptions::const_default(),
input,
output,
)));
DEVICE_REGISTRY
.serial_terminal
.register(terminal.clone(), Some(self.clone()))
.ok();
Ok(())
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
let output = self.inner.get().output();
let io = output.io.lock();
io.regs.IER.modify(IER::ERBFI::SET);
Ok(())
}
fn display_name(&self) -> &str {
"Synopsys DesignWare 8250 UART"
}
}
impl DebugSink for DwUart {
fn putc(&self, c: u8) -> Result<(), Error> {
self.inner.get().putc_to_output(c)
}
fn supports_control_sequences(&self) -> bool {
true
}
}
impl TerminalOutput for Inner {
fn write(&self, byte: u8) -> Result<(), Error> {
self.io.lock().send(byte);
Ok(())
}
fn write_multiple(&self, bytes: &[u8]) -> Result<usize, Error> {
let mut lock = self.io.lock();
for &byte in bytes {
lock.send(byte);
}
Ok(bytes.len())
}
}
device_tree_driver! {
compatible: ["snps,dw-apb-uart"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let irq = node.interrupt(0)?;
let clk_baud = node.named_clock("baudclk")?;
let clk_apb = node.named_clock("apb_pclk");
let rst = node.reset(0);
Some(Arc::new(DwUart {
base,
irq,
clk_baud,
clk_apb,
rst,
inner: OneTimeInit::new()
}))
}
}
}
+1
View File
@@ -65,6 +65,7 @@ extern crate compiler_builtins;
extern crate ygg_driver_ahci;
extern crate ygg_driver_net_rtl81xx;
extern crate ygg_driver_nvme;
extern crate ygg_driver_serial_8250;
extern crate ygg_driver_usb_xhci;
extern crate ygg_driver_virtio_blk;
extern crate ygg_driver_virtio_gpu;
+8
View File
@@ -154,6 +154,14 @@ impl RawStdin {
pub fn set_options(&mut self, options: TerminalOptionsImpl) -> io::Result<TerminalOptionsImpl> {
self.0.set_options(options)
}
pub fn options(&mut self) -> io::Result<TerminalOptionsImpl> {
self.0.options()
}
pub fn saved_options(&self) -> &TerminalOptionsImpl {
self.0.saved_options()
}
}
impl Read for RawStdin {
+6
View File
@@ -48,6 +48,8 @@ pub(crate) trait Pipe: Read + Write + AsRawFd + Sized {
pub(crate) trait RawStdin: Sized + Read + AsRawFd {
fn open() -> io::Result<Self>;
fn set_options(&mut self, options: TerminalOptionsImpl) -> io::Result<TerminalOptionsImpl>;
fn options(&mut self) -> io::Result<TerminalOptionsImpl>;
fn saved_options(&self) -> &TerminalOptionsImpl;
// fn new(stdin: &'a mut Stdin) -> io::Result<Self>;
}
@@ -66,6 +68,10 @@ pub trait TerminalOptions: Copy {
fn normal() -> Self;
fn raw() -> Self;
// Output
fn set_nl_to_crnl(&mut self, set: bool);
// Chars
fn erase_char(&self) -> u8;
fn word_erase_char(&self) -> u8;
fn eof_char(&self) -> u8;
+1 -1
View File
@@ -23,7 +23,7 @@ pub use mem::{FileMappingImpl, SharedMemoryImpl};
pub use pid::PidFdImpl;
pub use pipe::PipeImpl;
pub use poll::PollImpl;
pub use pty::{open as open_pty, PtyMasterImpl, PtySlaveImpl, TerminalOptionsImpl};
pub use pty::{PtyMasterImpl, PtySlaveImpl, TerminalOptionsImpl, open as open_pty};
pub use serial::SerialPortImpl;
pub use socket::{BorrowedAddressImpl, LocalPacketSocketImpl, OwnedAddressImpl};
pub use term::RawStdinImpl;
+1 -1
View File
@@ -1,5 +1,5 @@
use std::{
collections::{hash_map::Entry, HashMap},
collections::{HashMap, hash_map::Entry},
io,
mem::MaybeUninit,
os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd},
+8
View File
@@ -56,6 +56,14 @@ impl TerminalOptions for TerminalOptionsImpl {
this
}
fn set_nl_to_crnl(&mut self, set: bool) {
if set {
self.c_oflag |= libc::ONLCR;
} else {
self.c_oflag &= !libc::ONLCR;
}
}
fn eof_char(&self) -> u8 {
self.c_cc[libc::VEOF]
}
+8
View File
@@ -78,6 +78,14 @@ impl RawStdin for RawStdinImpl {
*t = options;
})
}
fn options(&mut self) -> io::Result<TerminalOptionsImpl> {
todo!()
}
fn saved_options(&self) -> &TerminalOptionsImpl {
todo!()
}
}
impl io::Read for RawStdinImpl {
+2 -2
View File
@@ -18,7 +18,7 @@ use std::{
fd::RawFd,
yggdrasil::{
process::CommandExt,
signal::{set_signal_handler, SignalHandler},
signal::{SignalHandler, set_signal_handler},
},
},
process::Command,
@@ -29,7 +29,7 @@ pub use mem::{FileMappingImpl, SharedMemoryImpl};
pub use pid::PidFdImpl;
pub use pipe::PipeImpl;
pub use poll::PollImpl;
pub use pty::{open as open_pty, PtyMasterImpl, PtySlaveImpl, TerminalOptionsImpl};
pub use pty::{PtyMasterImpl, PtySlaveImpl, TerminalOptionsImpl, open as open_pty};
pub use serial::SerialPortImpl;
pub use socket::{BorrowedAddressImpl, LocalPacketSocketImpl, OwnedAddressImpl};
pub use term::RawStdinImpl;
@@ -47,6 +47,14 @@ impl TerminalOptions for TerminalOptionsImpl {
}
}
fn set_nl_to_crnl(&mut self, set: bool) {
if set {
self.output |= TerminalOutputOptions::NL_TO_CRNL;
} else {
self.output &= !TerminalOutputOptions::NL_TO_CRNL;
}
}
fn eof_char(&self) -> u8 {
self.chars.eof
}
@@ -5,7 +5,7 @@ use std::{
};
use runtime::{
abi::net::{types::LocalSocketAddress, AncillaryMessage, MessageHeader, MessageHeaderMut},
abi::net::{AncillaryMessage, MessageHeader, MessageHeaderMut, types::LocalSocketAddress},
abi_serde::wire,
rt as yggdrasil_rt,
};
@@ -37,6 +37,13 @@ impl Inner {
let old = runtime::rt::io::terminal::update_terminal_options(fd, f)?;
Ok(old)
}
fn options(&self) -> io::Result<TerminalOptions> {
let fd = self.as_raw_fd();
let options = runtime::rt::io::terminal::get_terminal_options(fd)?;
Ok(options)
}
}
impl Read for Inner {
@@ -67,6 +74,14 @@ impl RawStdin for RawStdinImpl {
fn set_options(&mut self, options: TerminalOptions) -> io::Result<TerminalOptions> {
self.inner.update_options(|_| options)
}
fn options(&mut self) -> io::Result<TerminalOptions> {
self.inner.options()
}
fn saved_options(&self) -> &TerminalOptions {
&self.saved
}
}
impl io::Read for RawStdinImpl {
+8
View File
@@ -79,6 +79,14 @@ impl TerminalInput {
self.stdin.set_options(options)
}
pub fn options(&mut self) -> io::Result<TerminalOptionsImpl> {
self.stdin.options()
}
pub fn saved_options(&self) -> &TerminalOptionsImpl {
self.stdin.saved_options()
}
fn take(&mut self, count: usize) {
self.buffer.copy_within(count..self.buffer_len, 0);
self.buffer_len -= count;
+62 -27
View File
@@ -1,17 +1,38 @@
#![feature(yggdrasil_os, rustc_private)]
use std::{
env,
io::{self, BufRead, Write, stdin, stdout},
os::{
fd::AsRawFd,
yggdrasil::{io::terminal::start_terminal_session, rt::io::device},
},
io::{self, BufRead, Stdout, Write, stdin, stdout},
os::{fd::AsRawFd, yggdrasil::io::terminal::start_terminal_session},
path::PathBuf,
process::{Command, ExitCode},
thread,
time::Duration,
};
use clap::Parser;
use cross::io::{TerminalOptions, TerminalOptionsImpl};
use runtime::rt::io::terminal;
#[derive(Debug, Parser)]
struct Args {
#[clap(
short,
long,
help = "Serial terminal baud rate",
default_value_t = 115200
)]
baud: u32,
#[clap(
short = 'N',
long,
help = "Convert NL to CR+NL",
default_value_t = true
)]
nl_to_crnl: bool,
terminal: PathBuf,
}
fn login_readline<R: BufRead>(
reader: &mut R,
buf: &mut String,
@@ -20,14 +41,26 @@ fn login_readline<R: BufRead>(
reader.read_line(buf)
}
fn login_as(username: &str, _password: &str) -> Result<(), io::Error> {
fn login_as_inner(username: &str, _password: &str) -> Result<(), io::Error> {
let mut shell = Command::new("/bin/sh").arg("-l").spawn()?;
println!("Hello {:?}", username);
shell.wait()?;
Ok(())
}
fn login_attempt(erase: bool) -> Result<(), io::Error> {
fn login_as(
stdout: Stdout,
options: &TerminalOptionsImpl,
username: &str,
password: &str,
) -> Result<(), io::Error> {
let old_termios = terminal::update_terminal_options(stdout.as_raw_fd(), |_| *options)?;
let result = login_as_inner(username, password);
terminal::set_terminal_options(stdout.as_raw_fd(), &old_termios)?;
result
}
fn login_attempt(erase: bool, options: &TerminalOptionsImpl) -> Result<(), io::Error> {
let stdin = stdin();
let mut stdout = stdout();
@@ -44,25 +77,29 @@ fn login_attempt(erase: bool) -> Result<(), io::Error> {
return Ok(());
}
login_as(username.trim(), "")
login_as(stdout, options, username.trim(), "")
}
fn main() -> ExitCode {
logsink::setup_logging(false);
let args: Vec<_> = env::args().skip(1).collect();
if args.len() != 1 {
eprintln!("Usage: /sbin/login TTY");
return ExitCode::FAILURE;
}
let terminal = args[0].as_str();
let args = Args::parse();
// let args: Vec<_> = env::args().skip(1).collect();
// if args.len() != 1 {
// eprintln!("Usage: /sbin/login TTY");
// return ExitCode::FAILURE;
// }
// TODO check that `terminal` is a terminal
log::info!("Starting a session at {}", terminal);
log::info!("Starting a session at {}", args.terminal.display());
let mut success = false;
for _ in 0..3 {
if let Err(err) = unsafe { start_terminal_session(terminal) } {
log::error!("{terminal}: {err:?}");
eprintln!("Could not setup a session at {terminal}: {err:?}");
if let Err(err) = unsafe { start_terminal_session(&args.terminal) } {
log::error!("{}: {:?}", args.terminal.display(), err);
eprintln!(
"Could not setup a session at {}: {:?}",
args.terminal.display(),
err
);
} else {
success = true;
break;
@@ -74,21 +111,19 @@ fn main() -> ExitCode {
return ExitCode::FAILURE;
}
let mut terminal_options = TerminalOptionsImpl::normal();
terminal_options.set_nl_to_crnl(args.nl_to_crnl);
let mut attempt_number = 0;
loop {
log::debug!("Login attempt {}", attempt_number);
// "Attach" the terminal
let group_id = std::os::yggdrasil::process::group_id();
let mut buffer = [0; 8];
device::device_request::<device::SetTerminalGroup>(
stdin().as_raw_fd(),
&mut buffer,
&group_id,
)
.expect("Could not attach the terminal");
terminal::set_terminal_group(stdin().as_raw_fd(), group_id)
.expect("Could not set terminal group id");
if let Err(err) = login_attempt(attempt_number % 3 == 0) {
if let Err(err) = login_attempt(attempt_number % 3 == 0, &terminal_options) {
eprintln!("login: {}", err);
}
attempt_number += 1;
+1 -1
View File
@@ -1,6 +1,6 @@
use std::{
fs::File,
io::{self, stdin, stdout, BufRead, BufReader, BufWriter, Read, Stdin, Stdout, Write},
io::{self, BufRead, BufReader, BufWriter, Read, Stdin, Stdout, Write, stdin, stdout},
path::{Path, PathBuf},
};
+2 -2
View File
@@ -2,8 +2,8 @@ use std::process::ExitCode;
use clap::Parser;
use crypt::{
rsa::RsaKeyOptions, AsymmetricDecryptOptions, AsymmetricEncryptOptions, AsymmetricKeyOptions,
Error,
AsymmetricDecryptOptions, AsymmetricEncryptOptions, AsymmetricKeyOptions, Error,
rsa::RsaKeyOptions,
};
use rsa::pkcs8::{EncodePrivateKey, EncodePublicKey, LineEnding};
+1 -1
View File
@@ -4,9 +4,9 @@ use std::{
};
use rsa::{
Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey,
pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPrivateKey, EncodeRsaPublicKey},
pkcs8::LineEnding,
Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey,
};
use crate::{
+1 -1
View File
@@ -2,7 +2,7 @@
use std::{
fs,
io::{self, stdout, IsTerminal},
io::{self, IsTerminal, stdout},
path::PathBuf,
process::ExitCode,
};
+3 -3
View File
@@ -13,14 +13,14 @@ use std::{
sync::Arc,
};
use elf::{endian::AnyEndian, segment::ProgramHeader, symbol::Symbol, ElfStream};
use elf::{ElfStream, endian::AnyEndian, segment::ProgramHeader, symbol::Symbol};
use libterm::{Color, Term, TermKey};
use rangemap::RangeMap;
use yggdrasil_rt::{debug::DebugFrame, process::ProcessId};
use crate::state::State;
use crate::InstructionFormatter;
use crate::{comm::Comm, Error, Target};
use crate::state::State;
use crate::{Error, Target, comm::Comm};
pub struct SymbolResolver {
image: Arc<ImageInfo>,
+10 -8
View File
@@ -40,18 +40,20 @@ impl<T: Target> State<T> {
pub fn set_breakpoint(&mut self, address: u64) -> Result<(), Error> {
unsafe {
yggdrasil_rt::sys::debug_control(self.pid, &mut DebugOperation::SetBreakpoint(address.try_into().unwrap())).map_err(Error::DebugError)
yggdrasil_rt::sys::debug_control(
self.pid,
&mut DebugOperation::SetBreakpoint(address.try_into().unwrap()),
)
.map_err(Error::DebugError)
}
}
pub fn read_memory(&mut self, address: u64, buffer: &mut [u8]) -> Result<(), Error> {
let mut op = DebugOperation::ReadMemory { address: address.try_into().unwrap(), buffer };
unsafe {
yggdrasil_rt::sys::debug_control(
self.pid,
&mut op
).map_err(Error::DebugError)
}
let mut op = DebugOperation::ReadMemory {
address: address.try_into().unwrap(),
buffer,
};
unsafe { yggdrasil_rt::sys::debug_control(self.pid, &mut op).map_err(Error::DebugError) }
}
pub fn update_ip(&mut self, ip: usize) {
+1 -1
View File
@@ -3,7 +3,7 @@ use std::fmt::{self, Display};
use iced_x86::{Decoder, DecoderOptions, Formatter, GasFormatter, Instruction};
use yggdrasil_abi::arch::SavedFrame;
use crate::{debugger::SymbolResolver, InstructionFormatter, Target};
use crate::{InstructionFormatter, Target, debugger::SymbolResolver};
#[cfg(any(target_pointer_width = "32", rust_analyzer))]
const BITNESS: u32 = 32;
+1 -1
View File
@@ -1,10 +1,10 @@
use std::ops::RangeInclusive;
use crate::{
State,
buffer::{Buffer, SetMode},
config::Config,
error::Error,
State,
};
pub type CommandFn = fn(&mut State, &[&str]) -> Result<(), Error>;
+1 -1
View File
@@ -3,7 +3,7 @@ use libterm::TermKey;
use crate::{
buffer::Mode,
command::Action,
keymap::{bind1, bindn, KeyMap, KeySeq, PrefixNode},
keymap::{KeyMap, KeySeq, PrefixNode, bind1, bindn},
};
pub struct Config {
+4 -4
View File
@@ -8,19 +8,19 @@ use x25519_dalek::{EphemeralSecret, PublicKey};
use crate::{
crypt::{
self,
self, V1_CLIENT_RANDOM_LEN,
signature::VerificationMethod,
stream::ClientSocket,
symmetric::{data::Iv, SymmetricCipher},
V1_CLIENT_RANDOM_LEN,
symmetric::{SymmetricCipher, data::Iv},
},
proto::{Decode, DecodeError, Decoder, Encode, EncodeError, Encoder},
};
use super::{
ClientNegotiationMessage, ServerNegotiationMessage,
config::ClientConfig,
signature::{self, SignatureMethod},
symmetric, ClientNegotiationMessage, ServerNegotiationMessage,
symmetric,
};
pub(crate) struct Negotiation {
+3 -4
View File
@@ -1,16 +1,15 @@
use std::{collections::HashSet, path::PathBuf};
use crate::crypt::{
symmetric::{V1_CIPHER_AES_128_GCM, V1_CIPHER_AES_256_GCM, V1_CIPHER_CHACHA20POLY1305},
V1_KEX_X25519_DALEK,
symmetric::{V1_CIPHER_AES_128_GCM, V1_CIPHER_AES_256_GCM, V1_CIPHER_CHACHA20POLY1305},
};
use super::{
sig_algo_name,
V1_SIG_ED25519, sig_algo_name,
signature::{
fingerprint_sha256, SignEd25519, SignatureKeyStore, SignatureMethod, VerificationMethod,
SignEd25519, SignatureKeyStore, SignatureMethod, VerificationMethod, fingerprint_sha256,
},
V1_SIG_ED25519,
};
fn default_select_kex_algorithm(offer: &[u8]) -> Option<u8> {
+3 -3
View File
@@ -10,17 +10,17 @@ use x25519_dalek::{EphemeralSecret, PublicKey};
use crate::{
crypt::{
sig_algo_name, signature::fingerprint_sha256, stream::ClientSocket, symmetric::data::Iv,
ServerHello, ServerNegotiationMessage, V1_CLIENT_RANDOM_LEN,
ServerHello, ServerNegotiationMessage, V1_CLIENT_RANDOM_LEN, sig_algo_name,
signature::fingerprint_sha256, stream::ClientSocket, symmetric::data::Iv,
},
proto::{Decode, DecodeError, Decoder, Encode, EncodeError, Encoder},
};
use super::{
ClientNegotiationMessage,
config::ServerConfig,
signature::{SignatureMethod, VerificationMethod},
symmetric::{self, SymmetricCipher},
ClientNegotiationMessage,
};
pub struct ServerSocket {
+1 -2
View File
@@ -11,9 +11,8 @@ use crate::{
config::ClientConfig,
signature::{SignatureMethod, VerificationMethod},
symmetric::{
self,
self, SymmetricCipher,
data::{InboundEncryptedMessage, OutboundPlainMessage},
SymmetricCipher,
},
},
proto::{Decode, DecodeError, Decoder, Encode, EncodeError, Encoder},
@@ -2,15 +2,16 @@ use std::marker::PhantomData;
use aead::{KeyInit, KeySizeUser};
use aes::cipher::{BlockCipher, BlockEncrypt};
use aes_gcm::{aead::AeadMutInPlace, AesGcm};
use crypto_common::{typenum, BlockSizeUser};
use aes_gcm::{AesGcm, aead::AeadMutInPlace};
use crypto_common::{BlockSizeUser, typenum};
use crate::crypt::symmetric::{
CiphersuiteAlgorithm, Decrypter, Encrypter, Error,
data::{
DecryptionBuffer, EncryptionBuffer, InboundEncryptedMessage, InboundPlainMessage, Iv,
Nonce, NonceSize, OutboundEncryptedMessage, OutboundPlainMessage, PrefixedPayload,
},
make_aad, CiphersuiteAlgorithm, Decrypter, Encrypter, Error,
make_aad,
};
pub struct AesGcmAlgorithm<Aes>(PhantomData<Aes>);
@@ -93,9 +94,9 @@ where
#[cfg(test)]
mod tests {
use crate::crypt::symmetric::{
CiphersuiteAlgorithm,
aes_gcm::{AES128GCM, AES256GCM},
data::{InboundEncryptedMessage, Iv, OutboundPlainMessage},
CiphersuiteAlgorithm,
};
#[test]
@@ -2,11 +2,12 @@ use aead::{AeadMutInPlace, KeyInit, KeySizeUser};
use chacha20poly1305::ChaCha20Poly1305;
use crate::crypt::symmetric::{
CiphersuiteAlgorithm, Decrypter, Encrypter, Error,
data::{
DecryptionBuffer, EncryptionBuffer, InboundEncryptedMessage, InboundPlainMessage, Iv,
Nonce, OutboundEncryptedMessage, OutboundPlainMessage, PrefixedPayload,
},
make_aad, CiphersuiteAlgorithm, Decrypter, Encrypter, Error,
make_aad,
};
pub struct Chacha20Poly1305Algorithm;
@@ -78,9 +79,9 @@ impl Decrypter for Chacha20Poly1305Cipher {
#[cfg(test)]
mod tests {
use crate::crypt::symmetric::{
CiphersuiteAlgorithm,
chacha20poly1305::CHACHA20POLY1305,
data::{InboundEncryptedMessage, Iv, OutboundPlainMessage},
CiphersuiteAlgorithm,
};
#[test]
+1 -1
View File
@@ -2,10 +2,10 @@
#![feature(generic_const_exprs, portable_simd, if_let_guard, let_chains)]
#![allow(incomplete_features)]
pub mod socket;
pub mod crypt;
pub mod proto;
pub mod server;
pub mod socket;
pub enum Message<T> {
None,
+2 -2
View File
@@ -2,7 +2,7 @@
#![feature(let_chains)]
use std::{
io::{stderr, stdout, IsTerminal, Read, Stderr, Write},
io::{IsTerminal, Read, Stderr, Write, stderr, stdout},
ops::{Deref, DerefMut},
os::fd::AsRawFd,
};
@@ -20,7 +20,7 @@ use rsh::{
};
use std::{
io::{self, stdin, Stdin, Stdout},
io::{self, Stdin, Stdout, stdin},
net::{IpAddr, SocketAddr},
path::PathBuf,
process::ExitCode,
+1 -1
View File
@@ -1,5 +1,5 @@
use std::{
collections::{hash_map::Entry, HashMap},
collections::{HashMap, hash_map::Entry},
fmt,
hint::unreachable_unchecked,
io::{self, Read, Write},
+1
View File
@@ -0,0 +1 @@
+2 -2
View File
@@ -3,11 +3,11 @@ use std::{io::BufReader, marker::PhantomData, process::ExitCode};
use crate::{
builtin::{self, Envs},
error::Error,
exec::{exec_pipeline, wait_for_pipeline, Execution, InheritStdout, Input, Outcome, Output},
exec::{Execution, InheritStdout, Input, Outcome, Output, exec_pipeline, wait_for_pipeline},
syntax::parse::{BinaryOperator, ConditionalExpression, Expression},
};
use super::{env::Environment, ExpandedPipeline, ExpandedPipelineElement};
use super::{ExpandedPipeline, ExpandedPipelineElement, env::Environment};
pub fn evaluate_pipeline(
pipeline: &ExpandedPipeline,
+1 -1
View File
@@ -1,5 +1,5 @@
use std::{
collections::{hash_map::Entry, HashMap},
collections::{HashMap, hash_map::Entry},
fmt,
path::PathBuf,
};
+1 -1
View File
@@ -12,7 +12,7 @@ use std::{
#[cfg(any(rust_analyzer, target_os = "yggdrasil"))]
use std::os::yggdrasil::{
io::terminal::set_terminal_group,
process::{create_process_group, CommandExt},
process::{CommandExt, create_process_group},
};
#[cfg(any(rust_analyzer, unix))]
+2 -3
View File
@@ -18,7 +18,6 @@ use std::{
use clap::Parser;
use command::env::Environment;
use cross::io::{TerminalOptions, TerminalOptionsImpl};
use error::Error;
use exec::Outcome;
use stuff::readline::Readline;
@@ -135,8 +134,8 @@ fn run(mut input: ShellInput, env: &mut Environment) -> Result<(), Error> {
}
};
let old_termios = if let ShellInput::Interactive(interactive) = &mut input {
let new = TerminalOptionsImpl::normal();
Some(interactive.stdin_mut().set_options(new)?)
let termios = *interactive.stdin_mut().saved_options();
Some(interactive.stdin_mut().set_options(termios)?)
} else {
None
};
+4 -4
View File
@@ -1,6 +1,7 @@
use std::fmt;
use nom::{
IResult,
branch::alt,
bytes::{
complete::{self, tag},
@@ -10,7 +11,6 @@ use nom::{
combinator::{map, recognize, value, verify},
multi::{many0, many1},
sequence::{delimited, preceded, terminated, tuple},
IResult,
};
#[derive(Debug, PartialEq)]
@@ -493,9 +493,9 @@ impl fmt::Display for Token<'_> {
#[cfg(test)]
mod tests {
use crate::syntax::lex::{
lex_double_quote_word_segment, lex_literal_word_segment, lex_single_quote_word_segment,
lex_token, lex_word, DoubleQuotedSegment, Escape, Keyword, OutputRedirect,
OutputRedirectTarget, Punct, Redirect, Token, WordSegment, WordToken,
DoubleQuotedSegment, Escape, Keyword, OutputRedirect, OutputRedirectTarget, Punct,
Redirect, Token, WordSegment, WordToken, lex_double_quote_word_segment,
lex_literal_word_segment, lex_single_quote_word_segment, lex_token, lex_word,
};
use super::lex_tokens;
+5 -5
View File
@@ -217,7 +217,7 @@ fn parse_if(input: &str) -> Result<(&str, Expression), Error> {
return Err(Error::Expected {
expected: Token::Keyword(Keyword::Then),
got: then_or_semicolon,
})
});
}
}
}
@@ -269,7 +269,7 @@ fn parse_while(input: &str) -> Result<(&str, Expression), Error> {
return Err(Error::Expected {
expected: Token::Keyword(Keyword::Do),
got: do_or_semicolon,
})
});
}
}
}
@@ -319,7 +319,7 @@ fn parse_for(input: &str) -> Result<(&str, Expression), Error> {
return Err(Error::Expected {
expected: Token::Keyword(Keyword::Do),
got: do_or_semicolon,
})
});
}
}
}
@@ -628,8 +628,8 @@ mod tests {
InputRedirect, OutputRedirect, OutputRedirectTarget, Redirect, WordSegment, WordToken,
},
parse::{
parse_expression, parse_pipeline, parse_pipeline_element, BinaryOperator, Expression,
IfExpression, PipelineElement, PipelineExpression,
BinaryOperator, Expression, IfExpression, PipelineElement, PipelineExpression,
parse_expression, parse_pipeline, parse_pipeline_element,
},
};
+1 -1
View File
@@ -13,7 +13,7 @@ use runtime::{
rt::{
debug::debug_control,
process::ThreadEvent,
time::{get_monotonic_time, SystemTime},
time::{SystemTime, get_monotonic_time},
},
};
+1
View File
@@ -22,3 +22,4 @@ semver = { version = "1.0.22", features = ["serde"] }
fatfs = "0.3.6"
fscommon = "0.1.1"
indicatif = "0.17.9"
tempfile = "3.24.0"
+95
View File
@@ -0,0 +1,95 @@
use std::fs;
use tempfile::NamedTempFile;
use crate::{env::BuildEnv, error::Error, util::run_external_command};
const DTC_ARCHITECTURES: &[&str] = &["aarch64", "riscv64"];
fn find_all_device_trees(env: &BuildEnv) -> Vec<String> {
let mut res = vec![];
for &arch in DTC_ARCHITECTURES {
let Ok(dir) = fs::read_dir(env.workspace_root.join("etc/dtb").join(arch)) else {
continue;
};
for entry in dir {
let Ok(entry) = entry else {
continue;
};
let Ok(file_type) = entry.file_type() else {
continue;
};
if !file_type.is_file() {
continue;
}
let name = entry.file_name();
let Some(name) = name.to_str() else {
continue;
};
if !name.ends_with(".dts") {
continue;
}
res.push(format!("etc/dtb/{arch}/{name}"));
}
}
res
}
pub fn build_device_tree(env: &BuildEnv, name: &str) -> Result<String, Error> {
let Some((head, filename)) = name.rsplit_once("/") else {
log::error!("Invalid device tree path: {name:?}");
return Err(Error::UsageError);
};
let Some(filename) = filename.strip_suffix(".dts") else {
log::error!("Invalid device tree filename: {name:?}");
return Err(Error::UsageError);
};
let Some((_, arch)) = head.rsplit_once("/") else {
log::error!("Invalid device tree path: {name:?}");
return Err(Error::UsageError);
};
if !DTC_ARCHITECTURES.contains(&arch) {
log::error!("Unexpected dtb architecture {arch:?}: {name:?}");
return Err(Error::UsageError);
}
log::info!("Building device tree: {arch}/{filename}.dts");
let cpp_output = NamedTempFile::new()?.into_temp_path();
// let _ = env;
let output = format!("target/{arch}-unknown-none/dtb/{filename}.dtb");
fs::create_dir_all(format!("target/{arch}-unknown-none/dtb"))?;
run_external_command(
"cpp",
[
"-undef",
"-x",
"assembler-with-cpp",
&format!("-I{}/etc/dtb", env.workspace_root.display()),
name,
&format!("{}", cpp_output.display()),
],
false,
)?;
run_external_command(
"dtc",
[
"-O",
"dtb",
"-o",
&output,
&format!("{}", cpp_output.display()),
],
false,
)?;
drop(cpp_output);
Ok(output)
}
pub fn build_device_trees(env: &BuildEnv) -> Result<(), Error> {
let device_trees = find_all_device_trees(env);
for device_tree in device_trees {
build_device_tree(env, &device_tree)?;
}
Ok(())
}
+27 -4
View File
@@ -11,6 +11,7 @@ pub mod x86_64;
pub mod c;
mod cargo;
pub mod device_tree;
pub mod ports;
pub mod ygglibc;
// mod module;
@@ -39,8 +40,8 @@ pub struct KernelBin(pub PathBuf);
pub struct InitrdGenerated(pub PathBuf);
pub struct ImageBuilt(pub PathBuf);
pub enum AllBuilt {
Riscv64(KernelBin, InitrdGenerated),
AArch64(KernelBin, InitrdGenerated),
Riscv64(KernelBin, InitrdGenerated, Option<String>),
AArch64(KernelBin, InitrdGenerated, Option<String>),
X86_64(ImageBuilt),
}
@@ -71,6 +72,15 @@ pub fn build_all(env: &BuildEnv) -> Result<AllBuilt, Error> {
let check = check::check_build_env(env.arch)?;
let device_tree = if let Some(device_tree) = env.board.device_tree() {
Some(device_tree::build_device_tree(
env,
&format!("etc/dtb/{device_tree}.dts"),
)?)
} else {
None
};
// Kernel stuff
let kernel = build_kernel(env, check)?;
// Userspace stuff
@@ -78,8 +88,12 @@ pub fn build_all(env: &BuildEnv) -> Result<AllBuilt, Error> {
// Build target-specific image
let image = match env.arch {
Arch::riscv64 => AllBuilt::Riscv64(make_kernel_bin(env, kernel, check)?, initrd),
Arch::aarch64 => AllBuilt::AArch64(make_kernel_bin(env, kernel, check)?, initrd),
Arch::riscv64 => {
AllBuilt::Riscv64(make_kernel_bin(env, kernel, check)?, initrd, device_tree)
}
Arch::aarch64 => {
AllBuilt::AArch64(make_kernel_bin(env, kernel, check)?, initrd, device_tree)
}
Arch::x86_64 => AllBuilt::X86_64(x86_64::build_image(env, kernel, initrd)?),
};
@@ -172,6 +186,15 @@ pub fn clean_all(env: &BuildEnv, clean_toolchain: bool, repos: bool) -> Result<(
Ok(())
}
pub fn build_device_tree(env: &BuildEnv, name: &str) -> Result<(), Error> {
device_tree::build_device_tree(env, name)?;
Ok(())
}
pub fn build_device_trees(env: &BuildEnv) -> Result<(), Error> {
device_tree::build_device_trees(env)
}
pub fn build_toolchain(env: &BuildEnv, branch: &str) -> Result<(), Error> {
toolchain::fetch(env, branch)?;
toolchain::build(env)
+1 -1
View File
@@ -7,7 +7,7 @@ use std::{
use fscommon::BufStream;
use crate::{
build::{cargo::CargoBuilder, KernelBuilt},
build::{KernelBuilt, cargo::CargoBuilder},
env::BuildEnv,
error::Error,
util,
+9
View File
@@ -223,3 +223,12 @@ impl Arch {
}
}
}
impl Board {
pub fn device_tree(&self) -> Option<&str> {
match self {
Self::raspi4b => Some("aarch64/bcm2711-rpi-4-b"),
_ => None,
}
}
}
+2
View File
@@ -10,6 +10,8 @@ use crate::{build::ports::BuildStep, env::Board};
pub enum Error {
#[error("{0}")]
SystemError(#[from] io::Error),
#[error("Invalid command usage")]
UsageError,
#[error("Cargo command failed")]
CargoFailed,
#[error("Could not generate a processed kernel image")]
+15
View File
@@ -66,6 +66,12 @@ enum SubArgs {
#[clap(short, long, help = "Clean cloned repositories")]
repos: bool,
},
Dtc {
#[clap(short, long, help = "Build all device trees")]
all: bool,
#[clap(short, long, help = "Device tree to compile")]
name: Option<String>,
},
// #[clap(about = "Print `git status` for the components", alias = "gst")]
// GitStatus,
@@ -136,6 +142,15 @@ fn run(args: Args) -> Result<(), Error> {
SubArgs::Clippy => build::check_all(env, CheckAction::Clippy),
SubArgs::Test => build::test_all(env),
SubArgs::Clean { toolchain, repos } => build::clean_all(&env, toolchain, repos),
SubArgs::Dtc { all: true, .. } => build::build_device_trees(&env),
SubArgs::Dtc { all: false, name } => {
let Some(name) = name else {
eprintln!("No device tree specified");
return Err(Error::UsageError);
};
build::build_device_tree(&env, &name)
}
// SubArgs::GitStatus => util::git_status_all(&env),
SubArgs::Qemu {
qemu,
+25 -17
View File
@@ -5,9 +5,9 @@ use std::{
};
use qemu::{
aarch64,
Qemu, aarch64,
device::{IntelGigabitRev, QemuDevice, QemuDrive, QemuNic, QemuSerialTarget},
riscv64, x86_64, Qemu,
riscv64, x86_64,
};
use crate::{
@@ -146,6 +146,7 @@ fn run_aarch64(
devices: Vec<QemuDevice>,
kernel_bin: PathBuf,
initrd: PathBuf,
device_tree: Option<&str>,
) -> Result<Command, Error> {
let mut qemu = Qemu::new_aarch64();
if let Some(qemu_bin) = qemu_bin {
@@ -182,15 +183,8 @@ fn run_aarch64(
let mut command = qemu.into_command();
if env.board == Board::raspi4b {
// Provide the dtb
command.args([
"-dtb",
&format!(
"{}/etc/dtb/bcm2711-rpi-4-b.dtb",
env.workspace_root.display()
),
]);
if let Some(device_tree) = device_tree {
command.args(["-dtb", device_tree]);
}
Ok(command)
@@ -231,7 +225,9 @@ fn run_riscv64(
devices: Vec<QemuDevice>,
kernel: PathBuf,
initrd: PathBuf,
device_tree: Option<&str>,
) -> Result<Command, Error> {
let _ = device_tree;
let _ = config;
let _ = devices;
@@ -335,12 +331,24 @@ pub fn run(
add_devices_from_config(&mut devices, disk.as_ref(), &config)?;
let mut command = match built {
AllBuilt::Riscv64(KernelBin(kernel), InitrdGenerated(initrd)) => {
run_riscv64(&config, &env, qemu, devices, kernel, initrd)?
}
AllBuilt::AArch64(KernelBin(kernel), InitrdGenerated(initrd)) => {
run_aarch64(&config, &env, qemu, devices, kernel, initrd)?
}
AllBuilt::Riscv64(KernelBin(kernel), InitrdGenerated(initrd), device_tree) => run_riscv64(
&config,
&env,
qemu,
devices,
kernel,
initrd,
device_tree.as_deref(),
)?,
AllBuilt::AArch64(KernelBin(kernel), InitrdGenerated(initrd), device_tree) => run_aarch64(
&config,
&env,
qemu,
devices,
kernel,
initrd,
device_tree.as_deref(),
)?,
AllBuilt::X86_64(ImageBuilt(image)) => run_x86_64(&config, qemu, devices, image)?,
};
+1 -1
View File
@@ -1,7 +1,7 @@
use std::{
ffi::OsStr,
fs,
io::{stderr, Write},
io::{Write, stderr},
path::Path,
process::{Command, Stdio},
};