diff options
author | Yonghee Han <onstudy@samsung.com> | 2016-07-27 16:43:51 +0900 |
---|---|---|
committer | Yonghee Han <onstudy@samsung.com> | 2016-07-27 01:00:25 -0700 |
commit | 186efde2677c31fb40d154a81a5f3731eab52414 (patch) | |
tree | b43c1e7ee15fbdade66764b4b45f40dd3fad408e /roms | |
parent | a03c4728275d119af5f66c4a69e8d9d5a1730031 (diff) | |
download | qemu-186efde2677c31fb40d154a81a5f3731eab52414.tar.gz qemu-186efde2677c31fb40d154a81a5f3731eab52414.tar.bz2 qemu-186efde2677c31fb40d154a81a5f3731eab52414.zip |
Imported Upstream version 2.6.0upstream/2.6.0
Change-Id: I8e3ccf55257695533c385aa8706484c73a733251
Diffstat (limited to 'roms')
231 files changed, 8118 insertions, 3476 deletions
diff --git a/roms/Makefile b/roms/Makefile index 09e33b59e..7bd125273 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -35,7 +35,7 @@ powerpc_cross_prefix := $(call find-cross-prefix,powerpc) x86_64_cross_prefix := $(call find-cross-prefix,x86_64) # tag our seabios builds -SEABIOS_VERSION="$(shell cd seabios; git describe --tags --long) by qemu-project.org" +SEABIOS_EXTRAVERSION="-prebuilt.qemu-project.org" # # EfiRom utility is shipped with edk2 / tianocore, in BaseTools/ @@ -64,7 +64,6 @@ default: bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin cp seabios/builds/seabios-256k/bios.bin ../pc-bios/bios-256k.bin - cp seabios/builds/seabios-256k/src/fw/*dsdt.aml ../pc-bios/ seavgabios: $(patsubst %,seavgabios-%,$(vgabios_variants)) @@ -78,12 +77,12 @@ build-seabios-config-%: config.% mkdir -p seabios/builds/$* cp $< seabios/builds/$*/.config $(MAKE) -C seabios \ - VERSION=$(SEABIOS_VERSION) \ + EXTRAVERSION=$(SEABIOS_EXTRAVERSION) \ CROSS_COMPILE=$(x86_64_cross_prefix) \ KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \ OUT=$(CURDIR)/seabios/builds/$*/ oldnoconfig $(MAKE) -C seabios \ - VERSION=$(SEABIOS_VERSION) \ + EXTRAVERSION=$(SEABIOS_EXTRAVERSION) \ CROSS_COMPILE=$(x86_64_cross_prefix) \ KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \ OUT=$(CURDIR)/seabios/builds/$*/ all diff --git a/roms/SLOF/README b/roms/SLOF/README index 789504568..294458880 100644 --- a/roms/SLOF/README +++ b/roms/SLOF/README @@ -12,6 +12,7 @@ Index 2.4 Extending the Forth engine 3.0 Limitations 4.0 Submitting patches +5.0 Coding style 1.0 Introduction to Slimline Open Firmware @@ -247,6 +248,24 @@ confirm that you certify the Developer Certificate of Origin Version 1.1, see [3] for details. +5.0 Coding style +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +New C code submitted to SLOF should follow the coding style guidelines +for the Linux kernel [4] with the following exceptions: + +- in the event that you require a specific width, use a standard type + like int32_t, uint32_t, uint64_t, etc. Don't use Linux kernel internal + types like u32, __u32 or __le32. + +New Forth code should use 4 space indentations and no tabs. Patches for +the old code should keep the existing style which usually is +3 space indentation. + +New assembly code submitted to SLOF should follow the coding style +guidelines for the Linux kernel [4], i.e. indent with tabs, not with spaces. + + Documentation +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -258,3 +277,6 @@ Documentation [3] Developer Certificate of Origin Version 1.1 http://developercertificate.org/ + +[4] Linux kernel coding style + https://github.com/torvalds/linux/blob/master/Documentation/CodingStyle diff --git a/roms/SLOF/VERSION b/roms/SLOF/VERSION index c99837873..aded5537b 100644 --- a/roms/SLOF/VERSION +++ b/roms/SLOF/VERSION @@ -1 +1 @@ -20151103 +20160223 diff --git a/roms/SLOF/board-js2x/slof/Makefile b/roms/SLOF/board-js2x/slof/Makefile index fdc716fc6..4cdd5fa36 100644 --- a/roms/SLOF/board-js2x/slof/Makefile +++ b/roms/SLOF/board-js2x/slof/Makefile @@ -57,6 +57,7 @@ OF_FFS_FILES = \ $(SLOFBRDDIR)/attu.fs \ $(SLOFBRDDIR)/cpu.fs \ $(SLOFBRDDIR)/ioapic.fs \ + $(SLOFBRDDIR)/dma-function.fs \ $(SLOFBRDDIR)/pci-bridge_1022_7460.fs \ $(SLOFBRDDIR)/pci-device_1014_028c.fs \ $(SLOFBRDDIR)/pci-device_1014_02bd.fs \ @@ -82,7 +83,6 @@ OF_FFS_FILES = \ $(SLOFCMNDIR)/fs/scsi-host-helpers.fs \ $(SLOFCMNDIR)/fs/scsi-probe-helpers.fs \ $(SLOFCMNDIR)/fs/scsi-support.fs \ - $(SLOFCMNDIR)/fs/dma-function.fs \ $(SLOFCMNDIR)/fs/pci-device.fs \ $(SLOFCMNDIR)/fs/pci-bridge.fs \ $(SLOFCMNDIR)/fs/pci-properties.fs \ diff --git a/roms/SLOF/board-js2x/slof/dma-function.fs b/roms/SLOF/board-js2x/slof/dma-function.fs new file mode 100644 index 000000000..2e314cdaa --- /dev/null +++ b/roms/SLOF/board-js2x/slof/dma-function.fs @@ -0,0 +1,31 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2011 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +: dma-alloc ( ... size -- virt ) + \ ." dma-alloc called: " .s cr + alloc-mem +; + +: dma-free ( virt size -- ) + \ ." dma-free called: " .s cr + free-mem +; + +: dma-map-in ( ... virt size cacheable? -- devaddr ) + \ ." dma-map-in called: " .s cr + 2drop +; + +: dma-map-out ( virt devaddr size -- ) + \ ." dma-map-out called: " .s cr + 2drop drop +; diff --git a/roms/SLOF/board-qemu/slof/Makefile b/roms/SLOF/board-qemu/slof/Makefile index a3fe6abd0..a000a2519 100644 --- a/roms/SLOF/board-qemu/slof/Makefile +++ b/roms/SLOF/board-qemu/slof/Makefile @@ -66,8 +66,11 @@ USB_FFS_FILES = \ VIO_FFS_FILES = \ $(SLOFBRDDIR)/pci-device_1af4_1000.fs \ + $(SLOFBRDDIR)/pci-device_1af4_1041.fs \ $(SLOFBRDDIR)/pci-device_1af4_1001.fs \ + $(SLOFBRDDIR)/pci-device_1af4_1042.fs \ $(SLOFBRDDIR)/pci-device_1af4_1004.fs \ + $(SLOFBRDDIR)/pci-device_1af4_1048.fs \ $(SLOFBRDDIR)/pci-device_1af4_1009.fs \ $(SLOFBRDDIR)/pci-device_1af4_1050.fs \ $(SLOFBRDDIR)/vio-hvterm.fs \ diff --git a/roms/SLOF/board-qemu/slof/OF.fs b/roms/SLOF/board-qemu/slof/OF.fs index 561d89225..69ee5c122 100644 --- a/roms/SLOF/board-qemu/slof/OF.fs +++ b/roms/SLOF/board-qemu/slof/OF.fs @@ -134,10 +134,6 @@ check-boot-menu \ Grab rtas from qemu #include "rtas.fs" -390 cp - -#include "virtio.fs" - 3f0 cp #include "tree.fs" diff --git a/roms/SLOF/slof/fs/archsupport.fs b/roms/SLOF/board-qemu/slof/archsupport.fs index f564ab4e0..a8ace3cc5 100644 --- a/roms/SLOF/slof/fs/archsupport.fs +++ b/roms/SLOF/board-qemu/slof/archsupport.fs @@ -10,15 +10,16 @@ \ * IBM Corporation - initial implementation \ ****************************************************************************/ -\ 128KB FDT buffer size is enough to accommodate 255 CPU cores and 1TB of -\ maxmem specification. -20000 VALUE size +\ 2 MiB FDT buffer size is enough to accommodate 255 CPU cores +\ and 16 TiB of maxmem specification. +200000 CONSTANT cas-buffer-size : ibm,client-architecture-support ( vec -- err? ) \ Store require parameters in nvram \ to come back to right boot device \ Allocate memory for H_CALL - size alloc-mem ( vec memaddr ) - swap over size ( memaddr vec memaddr size ) + cas-buffer-size alloc-mem ( vec memaddr ) + dup 0= IF ." out of memory during ibm,client-architecture-support" cr THEN + swap over cas-buffer-size ( memaddr vec memaddr size ) \ make h_call to hypervisor hv-cas 0= IF ( memaddr ) dup l@ 1 >= IF \ Version number >= 1 @@ -34,5 +35,5 @@ ELSE TRUE THEN - >r size free-mem r> + >r cas-buffer-size free-mem r> ; diff --git a/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs b/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs index fb2463467..db0bb3fb8 100644 --- a/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs +++ b/roms/SLOF/board-qemu/slof/pci-device_1af4_1001.fs @@ -22,13 +22,4 @@ pci-io-enable s" virtio-block.fs" included -\ Allocate memory for virtio queue: -virtiodev 0 virtio-get-qsize virtio-vring-size -1000 CLAIM VALUE queue-addr - -\ Write queue address into device: -queue-addr c rshift -virtiodev vd>base @ 8 + -rl!-le - pci-device-disable diff --git a/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs b/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs index 03964a6db..9c8be249d 100644 --- a/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs +++ b/roms/SLOF/board-qemu/slof/pci-device_1af4_1009.fs @@ -22,13 +22,4 @@ pci-io-enable s" virtio-fs.fs" included -\ Allocate memory for virtio queue: -virtiodev 0 virtio-get-qsize virtio-vring-size -1000 CLAIM VALUE queue-addr - -\ Write queue address into device: -queue-addr c rshift -virtiodev vd>base @ 8 + -rl!-le - pci-device-disable diff --git a/roms/SLOF/board-qemu/slof/pci-device_1af4_1041.fs b/roms/SLOF/board-qemu/slof/pci-device_1af4_1041.fs new file mode 100644 index 000000000..552b0ef8a --- /dev/null +++ b/roms/SLOF/board-qemu/slof/pci-device_1af4_1041.fs @@ -0,0 +1,15 @@ +\ ***************************************************************************** +\ * Copyright (c) 2016 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Device ID 1041 is for virtio-net non-transitional device. +\ Include the driver for virtio-net +s" pci-device_1af4_1000.fs" included diff --git a/roms/SLOF/board-qemu/slof/pci-device_1af4_1042.fs b/roms/SLOF/board-qemu/slof/pci-device_1af4_1042.fs new file mode 100644 index 000000000..2b0a848d4 --- /dev/null +++ b/roms/SLOF/board-qemu/slof/pci-device_1af4_1042.fs @@ -0,0 +1,15 @@ +\ ***************************************************************************** +\ * Copyright (c) 2016 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Device ID 1042 is for virtio-blk non-transitional device. +\ Include the driver for virtio-blk +s" pci-device_1af4_1001.fs" included diff --git a/roms/SLOF/board-qemu/slof/pci-device_1af4_1048.fs b/roms/SLOF/board-qemu/slof/pci-device_1af4_1048.fs new file mode 100644 index 000000000..055ad8960 --- /dev/null +++ b/roms/SLOF/board-qemu/slof/pci-device_1af4_1048.fs @@ -0,0 +1,15 @@ +\ ***************************************************************************** +\ * Copyright (c) 2016 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Device ID 1048 is for virtio-scsi non-transitional device. +\ Include the driver for virtio-scsi +s" pci-device_1af4_1004.fs" included diff --git a/roms/SLOF/board-qemu/slof/tree.fs b/roms/SLOF/board-qemu/slof/tree.fs index 4aba4c53f..78dafab71 100644 --- a/roms/SLOF/board-qemu/slof/tree.fs +++ b/roms/SLOF/board-qemu/slof/tree.fs @@ -26,6 +26,8 @@ \ 2 encode-int s" #size-cells" property \ s" chrp" device-type +#include "archsupport.fs" + 480 cp \ See 3.6.5, and the PowerPC OF binding document. diff --git a/roms/SLOF/board-qemu/slof/virtio-block.fs b/roms/SLOF/board-qemu/slof/virtio-block.fs index ea388fb00..bc9013eea 100644 --- a/roms/SLOF/board-qemu/slof/virtio-block.fs +++ b/roms/SLOF/board-qemu/slof/virtio-block.fs @@ -23,8 +23,7 @@ FALSE VALUE initialized? INSTANCE VARIABLE deblocker -/vd-len BUFFER: virtiodev -virtiodev virtio-setup-vd +virtio-setup-vd VALUE virtiodev \ Quiesce the virtqueue of this device so that no more background \ transactions can be pending. diff --git a/roms/SLOF/board-qemu/slof/virtio-fs.fs b/roms/SLOF/board-qemu/slof/virtio-fs.fs index 8632b465f..3898d0b7d 100644 --- a/roms/SLOF/board-qemu/slof/virtio-fs.fs +++ b/roms/SLOF/board-qemu/slof/virtio-fs.fs @@ -20,8 +20,7 @@ FALSE VALUE initialized? 2000 CONSTANT VIRTFS-BUF-SIZE \ 8k -/vd-len BUFFER: virtiodev -virtiodev virtio-setup-vd +virtio-setup-vd VALUE virtiodev \ \ Support methods. diff --git a/roms/SLOF/board-qemu/slof/virtio-net.fs b/roms/SLOF/board-qemu/slof/virtio-net.fs index 412b34fa6..b16fffe39 100644 --- a/roms/SLOF/board-qemu/slof/virtio-net.fs +++ b/roms/SLOF/board-qemu/slof/virtio-net.fs @@ -16,20 +16,28 @@ s" network" device-type INSTANCE VARIABLE obp-tftp-package -/vd-len BUFFER: virtiodev -virtiodev virtio-setup-vd +virtio-setup-vd VALUE virtiodev 0 VALUE virtio-net-priv 0 VALUE open-count +\ Set up MAC address from config virtqueue +6 BUFFER: local-mac +: setup-mac ( -- ) + s" local-mac-address" get-node get-property not IF 2drop EXIT THEN + 6 0 DO + virtiodev i 1 virtio-get-config + local-mac i + c! + LOOP + local-mac 6 encode-bytes s" local-mac-address" property +; + : open ( -- okay? ) open-count 0= IF open IF \ my-unit 1 rtas-set-tce-bypass - s" local-mac-address" get-node get-property not IF - virtiodev virtio-net-open dup not IF ." virtio-net-open failed" EXIT THEN - drop TO virtio-net-priv - THEN - true + virtiodev virtio-net-open not IF ." virtio-net-open failed" false EXIT THEN + TO virtio-net-priv + setup-mac true ELSE false THEN @@ -77,17 +85,6 @@ virtiodev virtio-setup-vd s" ping" obp-tftp-package @ $call-method ; -\ Set up MAC address from config virtqueue -6 BUFFER: local-mac -: setup-mac ( -- ) - 6 0 DO - virtiodev i 1 virtio-get-config - local-mac i + c! - LOOP - local-mac 6 encode-bytes s" local-mac-address" property -; -setup-mac - : setup-alias ( -- ) " net" get-next-alias ?dup IF get-node node>path set-alias diff --git a/roms/SLOF/board-qemu/slof/virtio-scsi.fs b/roms/SLOF/board-qemu/slof/virtio-scsi.fs index ca5fb13aa..4fedeeeb1 100644 --- a/roms/SLOF/board-qemu/slof/virtio-scsi.fs +++ b/roms/SLOF/board-qemu/slof/virtio-scsi.fs @@ -22,8 +22,7 @@ FALSE CONSTANT virtio-scsi-debug FALSE VALUE initialized? -/vd-len BUFFER: virtiodev -virtiodev virtio-setup-vd +virtio-setup-vd VALUE virtiodev STRUCT \ virtio-scsi-config /l FIELD vs-cfg>num-queues diff --git a/roms/SLOF/board-qemu/slof/virtio.fs b/roms/SLOF/board-qemu/slof/virtio.fs deleted file mode 100644 index 818c1320e..000000000 --- a/roms/SLOF/board-qemu/slof/virtio.fs +++ /dev/null @@ -1,35 +0,0 @@ -\ ***************************************************************************** -\ * Copyright (c) 2011 IBM Corporation -\ * All rights reserved. -\ * This program and the accompanying materials -\ * are made available under the terms of the BSD License -\ * which accompanies this distribution, and is available at -\ * http://www.opensource.org/licenses/bsd-license.php -\ * -\ * Contributors: -\ * IBM Corporation - initial implementation -\ ****************************************************************************/ - -\ This struct must match "struct virtio_device" in virtio.h! -STRUCT - /n FIELD vd>base - /l FIELD vd>type -CONSTANT /vd-len - - -\ Initialize virtiodev structure for the current node -: virtio-setup-vd ( vdstruct -- ) - >r - \ Does it have a "class-code" property? If yes, assume we're a PCI device - s" class-code" get-node get-property 0= IF - \ Set up for PCI device interface - 2drop - s" 10 config-l@ translate-my-address 3 not AND" evaluate - ( io-base ) r@ vd>base ! - 0 r@ vd>type l! - ELSE - ." unsupported virtio interface!" cr - 1 r@ vd>type l! - THEN - r> drop -; diff --git a/roms/SLOF/clients/net-snk/app/netapps/netboot.c b/roms/SLOF/clients/net-snk/app/netapps/netboot.c index cf20b5915..bb1db03e3 100644 --- a/roms/SLOF/clients/net-snk/app/netapps/netboot.c +++ b/roms/SLOF/clients/net-snk/app/netapps/netboot.c @@ -332,7 +332,13 @@ int dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries, int flag int i = (int) retries+1; int rc = -1; - printf(" "); + printf(" Requesting information via DHCP%s: ", + flags == F_IPV4 ? "v4" : flags == F_IPV6 ? "v6" : ""); + + if (flags != F_IPV6) + dhcpv4_generate_transaction_id(); + if (flags != F_IPV4) + dhcpv6_generate_transaction_id(); do { printf("\b\b\b%03d", i-1); @@ -353,7 +359,6 @@ int dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries, int flag set_ipv6_address(fn_ip->fd, 0); rc = dhcpv6(ret_buffer, fn_ip); if (rc == 0) { - printf("\n"); memcpy(&fn_ip->own_ip6, get_ipv6_address(), 16); break; } @@ -362,11 +367,23 @@ int dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries, int flag if (rc != -1) /* either success or non-dhcp failure */ break; } while (1); - printf("\b\b\b\b"); + printf("\b\b\b\bdone\n"); return rc; } +/** + * Seed the random number generator with our mac and current timestamp + */ +static void seed_rng(uint8_t mac[]) +{ + unsigned int seed; + + asm volatile("mftbl %0" : "=r"(seed)); + seed ^= (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5]; + srand(seed); +} + int netboot(int argc, char *argv[]) { @@ -388,8 +405,7 @@ netboot(int argc, char *argv[]) int32_t block_size = strtol(argv[5], 0, 10); uint8_t own_mac[6]; - printf("\n"); - printf(" Bootloader 1.6 \n"); + puts("\n Initializing NIC"); memset(&fn_ip, 0, sizeof(filename_ip_t)); /*********************************************************** @@ -438,6 +454,8 @@ netboot(int argc, char *argv[]) // init ethernet layer set_mac_address(own_mac); + seed_rng(own_mac); + if (argc > 6) { parse_args(argv[6], &obp_tftp_args); if(obp_tftp_args.bootp_retries - rc < DEFAULT_BOOT_RETRIES) @@ -468,10 +486,8 @@ netboot(int argc, char *argv[]) } } else if (ip_version == 6) { - if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16) != 0 - && memcmp(&obp_tftp_args.si6addr, null_ip6, 16) != 0 + if (memcmp(&obp_tftp_args.si6addr, null_ip6, 16) != 0 && obp_tftp_args.filename[0] != 0) { - memcpy(&fn_ip.server_ip6.addr[0], &obp_tftp_args.si6addr.addr, 16); obp_tftp_args.ip_init = IP_INIT_IPV6_MANUAL; @@ -484,7 +500,6 @@ netboot(int argc, char *argv[]) // construction of fn_ip from parameter switch(obp_tftp_args.ip_init) { case IP_INIT_BOOTP: - printf(" Requesting IP address via BOOTP: "); // if giaddr in not specified, then we have to identify // the BOOTP server via broadcasts if(memcmp(obp_tftp_args.giaddr, null_ip, 4) == 0) { @@ -499,19 +514,25 @@ netboot(int argc, char *argv[]) rc = bootp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries); break; case IP_INIT_DHCP: - printf(" Requesting IP address via DHCPv4: "); rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, F_IPV4); break; case IP_INIT_DHCPV6_STATELESS: - printf(" Requesting information via DHCPv6: "); rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, F_IPV6); break; case IP_INIT_IPV6_MANUAL: - set_ipv6_address(fn_ip.fd, &obp_tftp_args.ci6addr); + if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16)) { + set_ipv6_address(fn_ip.fd, &obp_tftp_args.ci6addr); + } else { + /* + * If no client address has been specified, then + * use a link-local or stateless autoconfig address + */ + set_ipv6_address(fn_ip.fd, NULL); + memcpy(&fn_ip.own_ip6, get_ipv6_address(), 16); + } break; case IP_INIT_DEFAULT: - printf(" Requesting IP address via DHCP: "); rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries, 0); break; case IP_INIT_NONE: @@ -548,10 +569,15 @@ netboot(int argc, char *argv[]) return -101; } - if(ip_version == 4) - printf("%d.%d.%d.%d\n", + if (ip_version == 4) { + printf(" Using IPv4 address: %d.%d.%d.%d\n", ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF), ((fn_ip.own_ip >> 8) & 0xFF), ( fn_ip.own_ip & 0xFF)); + } else if (ip_version == 6) { + char ip6_str[40]; + ipv6_to_str(fn_ip.own_ip6.addr, ip6_str); + printf(" Using IPv6 address: %s\n", ip6_str); + } if (rc == -2) { sprintf(buf, @@ -818,7 +844,7 @@ int parse_tftp_args(char buffer[], char *server_ip, char filename[], int fd, tmp = raw + 7; tmp[j] = '\0'; strcpy(domainname, tmp); - if (dns_get_ip(fd, (int8_t *)domainname, server_ip6, 6) == 0) { + if (dns_get_ip(fd, domainname, server_ip6, 6) == 0) { printf("\n DNS failed for IPV6\n"); return -1; } diff --git a/roms/SLOF/clients/net-snk/app/netlib/bootp.c b/roms/SLOF/clients/net-snk/app/netlib/bootp.c index 1bc6efe5b..6d58cef7d 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/bootp.c +++ b/roms/SLOF/clients/net-snk/app/netlib/bootp.c @@ -232,7 +232,7 @@ bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) int i = (int) retries+1; fn_ip->own_ip = 0; - printf(" "); + printf(" Requesting IP address via BOOTP: "); response_buffer = ret_buffer; @@ -249,6 +249,7 @@ bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) * in case the previous one was lost. And because we don't * trust the network cable we keep on doing this 30 times */ } while (receive_bootp(fn_ip) != 0); - printf("\b\b\b"); + + printf("\b\b\bdone\n"); return 0; } diff --git a/roms/SLOF/clients/net-snk/app/netlib/dhcp.c b/roms/SLOF/clients/net-snk/app/netlib/dhcp.c index 5f26f3afb..7e2e88ccf 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/dhcp.c +++ b/roms/SLOF/clients/net-snk/app/netlib/dhcp.c @@ -11,7 +11,7 @@ *****************************************************************************/ -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ +/******************************* ALGORITHMS ******************************/ /** \file dhcp.c <pre> * **************** State-transition diagram for DHCP client ************* @@ -41,13 +41,14 @@ * </pre> */ -/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/ +/********************** DEFINITIONS & DECLARATIONS ***********************/ #include <dhcp.h> #include <ethernet.h> #include <ipv4.h> #include <udp.h> #include <dns.h> +#include <netapps/args.h> #include <stdio.h> #include <string.h> @@ -110,11 +111,11 @@ static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63}; * If flag[i] == TRUE then field for i-th option retains valid value and * information from this field may retrived (in case of receiving) or will * be transmitted (in case of transmitting). - * + * */ typedef struct { uint8_t flag[256]; /**< Show if corresponding opt. is valid */ - uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th + uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th option will be requested from server */ uint32_t server_ID; /**< o.54 Identifies DHCP-server */ uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */ @@ -132,65 +133,57 @@ typedef struct { static uint8_t dhcp_state; -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ - -static int32_t -dhcp_attempt(int fd); +/***************************** PROTOTYPES ********************************/ -static int32_t -dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct); +static int32_t dhcp_attempt(int fd); -static int32_t -dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, - dhcp_options_t * opt_struct); +static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct); -static int8_t -dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, - uint8_t src_options[], uint32_t src_len); +static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, + dhcp_options_t * opt_struct); -static int8_t -dhcp_find_option(uint8_t options[], uint32_t len, - uint8_t op_code, uint32_t * op_offset); - -static void -dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, - uint8_t * new_option); +static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, + uint8_t src_options[], uint32_t src_len); -static void -dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, - uint32_t dst_offset, uint8_t * new_option); +static int8_t dhcp_find_option(uint8_t options[], uint32_t len, + uint8_t op_code, uint32_t * op_offset); -static void -dhcp_send_discover(int fd); +static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, + uint8_t * new_option); -static void -dhcp_send_request(int fd); +static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, + uint32_t dst_offset, uint8_t * new_option); -static uint8_t -strtoip(int8_t * str, uint32_t * ip); +static void dhcp_send_discover(int fd); +static void dhcp_send_request(int fd); -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/ +/***************************** LOCAL VARIABLES ***************************/ static uint8_t ether_packet[ETH_MTU_SIZE]; static uint32_t dhcp_own_ip = 0; static uint32_t dhcp_server_ip = 0; static uint32_t dhcp_siaddr_ip = 0; -static int8_t dhcp_filename[256]; -static int8_t dhcp_tftp_name[256]; +static char dhcp_filename[256]; +static char dhcp_tftp_name[256]; +static uint32_t dhcp_xid; static char * response_buffer; -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/ +/***************************** IMPLEMENTATION ****************************/ -int32_t -dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) { +void dhcpv4_generate_transaction_id(void) +{ + dhcp_xid = (rand() << 16) ^ rand(); +} +int32_t dhcpv4(char *ret_buffer, filename_ip_t *fn_ip) +{ uint32_t dhcp_tftp_ip = 0; int fd = fn_ip->fd; - strcpy((char *) dhcp_filename, ""); - strcpy((char *) dhcp_tftp_name, ""); + strcpy(dhcp_filename, ""); + strcpy(dhcp_tftp_name, ""); response_buffer = ret_buffer; @@ -204,11 +197,11 @@ dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) { dhcp_siaddr_ip = fn_ip->server_ip; } if(fn_ip->filename[0] != 0) { - strcpy((char *) dhcp_filename, (char *) fn_ip->filename); + strcpy(dhcp_filename, (char *) fn_ip->filename); } // TFTP SERVER - if (!strlen((char *) dhcp_tftp_name)) { + if (!strlen(dhcp_tftp_name)) { if (!dhcp_siaddr_ip) { // ERROR: TFTP name is not presented return -3; @@ -219,9 +212,9 @@ dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) { } else { // TFTP server defined by its name - if (!strtoip(dhcp_tftp_name, &(dhcp_tftp_ip))) { - if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&(dhcp_tftp_ip), 4)) { - // DNS error - can't obtain TFTP-server name + if (!strtoip(dhcp_tftp_name, (char *)&dhcp_tftp_ip)) { + if (!dns_get_ip(fd, dhcp_tftp_name, (uint8_t *)&dhcp_tftp_ip, 4)) { + // DNS error - can't obtain TFTP-server name // Use TFTP-ip from siaddr field, if presented if (dhcp_siaddr_ip) { dhcp_tftp_ip = dhcp_siaddr_ip; @@ -237,7 +230,7 @@ dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) { // Store configuration info into filename_ip strucutre fn_ip -> own_ip = dhcp_own_ip; fn_ip -> server_ip = dhcp_tftp_ip; - strcpy((char *) fn_ip -> filename, (char *) dhcp_filename); + strcpy((char *) fn_ip -> filename, dhcp_filename); return 0; } @@ -245,8 +238,8 @@ dhcpv4(char *ret_buffer, filename_ip_t * fn_ip) { /** * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram */ -static int32_t -dhcp_attempt(int fd) { +static int32_t dhcp_attempt(int fd) +{ int sec; // Send DISCOVER message and switch DHCP-client to SELECT state @@ -270,7 +263,7 @@ dhcp_attempt(int fd) { } while (get_timer() > 0); } - // timeout + // timeout return 0; } @@ -278,7 +271,7 @@ dhcp_attempt(int fd) { * DHCP: Supplements DHCP-message with options stored in structure. * For more information about option coding see dhcp_options_t. * - * @param opt_field Points to the "vend" field of DHCP-message + * @param opt_field Points to the "vend" field of DHCP-message * (destination) * @param opt_struct this structure stores info about the options which * will be added to DHCP-message (source) @@ -286,8 +279,8 @@ dhcp_attempt(int fd) { * FALSE - error condition occurs. * @see dhcp_options_t */ -static int32_t -dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) { +static int32_t dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) +{ uint8_t * options = opt_field; uint16_t i, sum; // used to define is any options set @@ -380,7 +373,7 @@ dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) { * DHCP: Extracts encoded options from DHCP-message into the structure. * For more information about option coding see dhcp_options_t. * - * @param opt_field Points to the "options" field of DHCP-message + * @param opt_field Points to the "options" field of DHCP-message * (source). * @param opt_len Length of "options" field. * @param opt_struct this structure stores info about the options which @@ -389,10 +382,10 @@ dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) { * FALSE - error condition occurs. * @see dhcp_options_t */ -static int32_t -dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, - dhcp_options_t * opt_struct) { - int32_t offset = 0; +static int32_t dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, + dhcp_options_t * opt_struct) +{ + uint32_t offset = 0; memset(opt_struct, 0, sizeof(dhcp_options_t)); @@ -407,30 +400,30 @@ dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, switch(opt_field[offset]) { case DHCP_OVERLOAD : opt_struct -> overload = opt_field[offset + 2]; - offset += 2 + opt_field[offset + 1]; + offset += 2 + opt_field[offset + 1]; break; case DHCP_REQUESTED_IP : opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2)); - offset += 2 + opt_field[offset + 1]; + offset += 2 + opt_field[offset + 1]; break; case DHCP_MASK : opt_struct -> flag[DHCP_MASK] = 1; opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2)); - offset += 2 + opt_field[offset + 1]; + offset += 2 + opt_field[offset + 1]; break; case DHCP_DNS : opt_struct -> flag[DHCP_DNS] = 1; opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2)); - offset += 2 + opt_field[offset + 1]; + offset += 2 + opt_field[offset + 1]; break; case DHCP_ROUTER : opt_struct -> flag[DHCP_ROUTER] = 1; opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2)); - offset += 2 + opt_field[offset + 1]; + offset += 2 + opt_field[offset + 1]; break; case DHCP_MSG_TYPE : @@ -492,11 +485,12 @@ dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len, * FALSE - error condition occurs. */ static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, - uint8_t src_options[], uint32_t src_len) { - int32_t dst_offset, src_offset = 0; + uint8_t src_options[], uint32_t src_len) +{ + uint32_t dst_offset, src_offset = 0; // remove ENDOPT if presented - if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, (uint32_t *) &dst_offset)) + if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, &dst_offset)) * dst_len = dst_offset; while (src_offset < src_len) { @@ -509,7 +503,7 @@ static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, default: if (dhcp_find_option(dst_options, * dst_len, src_options[src_offset], - (uint32_t *) &dst_offset)) { + &dst_offset)) { dhcp_combine_option(dst_options, dst_len, dst_offset, (uint8_t *) src_options + @@ -522,7 +516,7 @@ static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, } } - if (src_offset == src_len) + if (src_offset == src_len) return 1; return 0; } @@ -540,7 +534,8 @@ static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len, * FALSE - option wasn't find. */ static int8_t dhcp_find_option(uint8_t options[], uint32_t len, - uint8_t op_code, uint32_t * op_offset) { + uint8_t op_code, uint32_t * op_offset) +{ uint32_t srch_offset = 0; * op_offset = 0; @@ -568,9 +563,9 @@ static int8_t dhcp_find_option(uint8_t options[], uint32_t len, * @param dst_len length of the "options" field (modified) * @param new_option points to an option in another list (src) */ -static void -dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, - uint8_t * new_option) { +static void dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, + uint8_t * new_option) +{ memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1))); * dst_len += 2 + *(new_option + 1); } @@ -586,10 +581,9 @@ dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len, * @param dst_offset offset of the option from beginning of the list * @param new_option points to an option in another list (src) */ -static void -dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, - uint32_t dst_offset, uint8_t * new_option) { - +static void dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, + uint32_t dst_offset, uint8_t * new_option) +{ uint8_t tmp_buffer[1024]; // use to provide safe memcpy uint32_t tail_len; @@ -612,8 +606,8 @@ dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, /** * DHCP: Sends DHCP-Discover message. Looks for DHCP servers. */ -static void -dhcp_send_discover(int fd) { +static void dhcp_send_discover(int fd) +{ uint32_t packetsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct btphdr); struct btphdr *btph; @@ -627,6 +621,7 @@ dhcp_send_discover(int fd) { btph -> op = 1; btph -> htype = 1; btph -> hlen = 6; + btph -> xid = dhcp_xid; memcpy(btph -> chaddr, get_mac_address(), 6); memset(&opt, 0, sizeof(dhcp_options_t)); @@ -655,8 +650,8 @@ dhcp_send_discover(int fd) { /** * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP. */ -static void -dhcp_send_request(int fd) { +static void dhcp_send_request(int fd) +{ uint32_t packetsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct btphdr); struct btphdr *btph; @@ -670,6 +665,7 @@ dhcp_send_request(int fd) { btph -> op = 1; btph -> htype = 1; btph -> hlen = 6; + btph -> xid = dhcp_xid; memcpy(btph -> chaddr, get_mac_address(), 6); memset(&opt, 0, sizeof(dhcp_options_t)); @@ -704,7 +700,8 @@ dhcp_send_request(int fd) { /** * DHCP: Sends DHCP-Release message. Releases occupied IP. */ -void dhcp_send_release(int fd) { +void dhcp_send_release(int fd) +{ uint32_t packetsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct btphdr); struct btphdr *btph; @@ -718,6 +715,7 @@ void dhcp_send_release(int fd) { btph -> op = 1; btph -> htype = 1; btph -> hlen = 6; + btph -> xid = dhcp_xid; strcpy((char *) btph -> file, ""); memcpy(btph -> chaddr, get_mac_address(), 6); btph -> ciaddr = htonl(dhcp_own_ip); @@ -730,7 +728,7 @@ void dhcp_send_release(int fd) { dhcp_encode_options(btph -> vend, &opt); - fill_udphdr(ðer_packet[sizeof(struct iphdr)], + fill_udphdr(ðer_packet[sizeof(struct iphdr)], sizeof(struct btphdr) + sizeof(struct udphdr), UDPPORT_BOOTPC, UDPPORT_BOOTPS); fill_iphdr(ether_packet, sizeof(struct btphdr) + @@ -753,18 +751,21 @@ void dhcp_send_release(int fd) { * @see btphdr */ -int8_t -handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) { +int8_t handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) +{ struct btphdr * btph; struct iphdr * iph; dhcp_options_t opt; - memset(&opt, 0, sizeof(dhcp_options_t)); + memset(&opt, 0, sizeof(dhcp_options_t)); btph = (struct btphdr *) packet; iph = (struct iphdr *) packet - sizeof(struct udphdr) - sizeof(struct iphdr); - if (btph -> op != 2) - return -1; // it is not Boot Reply + + if (btph->op != 2) + return -1; /* It is not a Bootp/DHCP reply */ + if (btph->xid != dhcp_xid) + return -1; /* The transaction ID does not match */ if (memcmp(btph -> vend, dhcp_magic, 4)) { // It is BootP - RFC 951 @@ -788,7 +789,7 @@ handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) { } - // decode options + // decode options if (!dhcp_decode_options(btph -> vend, packetsize - sizeof(struct btphdr) + sizeof(btph -> vend), &opt)) { @@ -902,7 +903,7 @@ handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) { else { strcpy((char *) dhcp_filename, ""); if (opt.overload != DHCP_OVERLOAD_FILE && - opt.overload != DHCP_OVERLOAD_BOTH && + opt.overload != DHCP_OVERLOAD_BOTH && strlen((char *) btph -> file)) { strncpy((char *) dhcp_filename, (char *) btph->file, @@ -952,47 +953,3 @@ handle_dhcp(int fd, uint8_t * packet, int32_t packetsize) { return 0; } - -/** - * DHCP: Converts "255.255.255.255" -> 32-bit long IP - * - * @param str string to be converted - * @param ip in case of SUCCESS - 32-bit long IP - in case of FAULT - zero - * @return TRUE - IP converted successfully; - * FALSE - error condition occurs (e.g. bad format) - */ -static uint8_t -strtoip(int8_t * str, uint32_t * ip) { - int8_t ** ptr = &str; - int16_t i = 0, res, len; - char octet[256]; - - * ip = 0; - - while (**ptr != 0) { - if (i > 3 || !isdigit(**ptr)) - return 0; - if (strstr((char *) * ptr, ".") != NULL) { - len = (int16_t) ((int8_t *) strstr((char *) * ptr, ".") - - (int8_t *) (* ptr)); - strncpy(octet, (char *) * ptr, len); octet[len] = 0; - * ptr += len; - } - else { - strcpy(octet, (char *) * ptr); - * ptr += strlen(octet); - } - res = strtol(octet, NULL, 10); - if ((res > 255) || (res < 0)) - return 0; - * ip = ((* ip) << 8) + res; - i++; - if (** ptr == '.') - (*ptr)++; - } - - if (i != 4) - return 0; - return 1; -} diff --git a/roms/SLOF/clients/net-snk/app/netlib/dhcp.h b/roms/SLOF/clients/net-snk/app/netlib/dhcp.h index 69dd49d4a..54fb1eed3 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/dhcp.h +++ b/roms/SLOF/clients/net-snk/app/netlib/dhcp.h @@ -43,6 +43,7 @@ struct btphdr { uint8_t vend[64]; /**< Optional parameters field (DHCP-options) */ }; +void dhcpv4_generate_transaction_id(void); int bootp(char *ret_buffer, filename_ip_t *, unsigned int); int dhcpv4(char *ret_buffer, filename_ip_t *); void dhcp_send_release(int fd); diff --git a/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c b/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c index 4deef30f2..d0a22d555 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c +++ b/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c @@ -27,13 +27,15 @@ static uint8_t tid[3]; static uint32_t dhcpv6_state = -1; static filename_ip_t *my_fn_ip; -static void -generate_transaction_id(void) +static struct ip6addr_list_entry all_dhcpv6_ll; /* All DHCPv6 servers address */ + +void +dhcpv6_generate_transaction_id(void) { - /* TODO: as per RFC 3315 transaction IDs should be generated randomly */ - tid[0] = 1; - tid[1] = 2; - tid[2] = 4; + /* As per RFC 3315 transaction IDs should be generated randomly */ + tid[0] = rand(); + tid[1] = rand(); + tid[2] = rand(); } static void @@ -45,8 +47,6 @@ send_info_request(int fd) memset(ether_packet, 0, ETH_MTU_SIZE); - generate_transaction_id(); - /* Get an IPv6 packet */ payload_length = sizeof(struct udphdr) + sizeof(struct dhcp_message_header); fill_ip6hdr (ether_packet + sizeof(struct ethhdr), @@ -72,16 +72,14 @@ send_info_request(int fd) dhcph->option.el_time.length = 2; dhcph->option.el_time.time = 0x190; /* 4000 ms */ dhcph->option.option_request_option.code = DHCPV6_OPTION_ORO; - dhcph->option.option_request_option.length= 6; + dhcph->option.option_request_option.length = DHCPV6_OPTREQUEST_NUMOPTS * 2; dhcph->option.option_request_option.option_code[0] = DHCPV6_OPTION_DNS_SERVERS; dhcph->option.option_request_option.option_code[1] = DHCPV6_OPTION_DOMAIN_LIST; dhcph->option.option_request_option.option_code[2] = DHCPV6_OPTION_BOOT_URL; - send_ipv6(fd, ether_packet + sizeof(struct ethhdr), - sizeof(struct ethhdr)+ sizeof(struct ip6hdr) - + sizeof(struct udphdr) - + sizeof( struct dhcp_message_header) ); + sizeof(struct ip6hdr) + sizeof(struct udphdr) + + sizeof(struct dhcp_message_header)); } static int32_t @@ -119,6 +117,9 @@ dhcpv6 ( char *ret_buffer, void *fn_ip) { int fd; + all_dhcpv6_ll.addr.part.prefix = 0xff02000000000000ULL; + all_dhcpv6_ll.addr.part.interface_id = 0x10002ULL; + my_fn_ip = (filename_ip_t *) fn_ip; fd = my_fn_ip->fd; @@ -129,8 +130,7 @@ dhcpv6 ( char *ret_buffer, void *fn_ip) return 0; } -static struct dhcp6_received_options * -dhcp6_process_options (uint8_t *option, int32_t option_length) +static void dhcp6_process_options (uint8_t *option, int32_t option_length) { struct dhcp_boot_url *option_boot_url; struct client_identifier *option_clientid; @@ -138,24 +138,19 @@ dhcp6_process_options (uint8_t *option, int32_t option_length) struct dhcp_dns *option_dns; struct dhcp_dns_list *option_dns_list; struct dhcp6_gen_option *option_gen; - struct dhcp6_received_options *received_options; char buffer[256]; - - received_options = malloc (sizeof(struct dhcp6_received_options)); while (option_length > 0) { switch ((uint16_t) *(option+1)) { case DHCPV6_OPTION_CLIENTID: option_clientid = (struct client_identifier *) option; option = option + option_clientid->length + 4; option_length = option_length - option_clientid->length - 4; - received_options->client_id = 1; break; case DHCPV6_OPTION_SERVERID: option_serverid = (struct server_identifier *) option; option = option + option_serverid->length + 4; option_length = option_length - option_serverid->length - 4; - received_options->server_id = 1; break; case DHCPV6_OPTION_DNS_SERVERS: option_dns = (struct dhcp_dns *) option; @@ -184,7 +179,7 @@ dhcp6_process_options (uint8_t *option, int32_t option_length) (char *)my_fn_ip->filename, (int)my_fn_ip->fd, option_boot_url->length) == -1) - return NULL; + return; break; default: option_gen = (struct dhcp6_gen_option *) option; @@ -192,8 +187,6 @@ dhcp6_process_options (uint8_t *option, int32_t option_length) option_length = option_length - option_gen->length - 4; } } - - return received_options; } uint32_t @@ -205,6 +198,9 @@ handle_dhcpv6(uint8_t * packet, int32_t packetsize) struct dhcp_message_reply *reply; reply = (struct dhcp_message_reply *) packet; + if (memcmp(reply->transaction_id, tid, 3)) + return -1; /* Wrong transaction ID */ + if (reply->type == 7) dhcpv6_state = DHCP_STATUSCODE_SUCCESS; diff --git a/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h b/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h index 078a9f11f..fb77da648 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h +++ b/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.h @@ -77,6 +77,7 @@ #define DUID_LL 3 /* DUID based on Link-layer Address */ /* Prototypes */ +void dhcpv6_generate_transaction_id(void); int32_t dhcpv6 ( char *ret_buffer, void *fn_ip); uint32_t handle_dhcpv6(uint8_t * , int32_t); @@ -102,6 +103,8 @@ struct server_identifier { uint8_t mac[6]; }; +#define DHCPV6_OPTREQUEST_NUMOPTS 3 + struct dhcp_info_request { struct client_identifier client_id; struct elapsed_time { @@ -112,7 +115,7 @@ struct dhcp_info_request { struct option_request { uint16_t code; uint16_t length; - uint16_t option_code[5]; + uint16_t option_code[DHCPV6_OPTREQUEST_NUMOPTS]; } option_request_option; }; @@ -141,12 +144,6 @@ struct dhcp_boot_url { uint8_t url[256]; }; -struct dhcp6_received_options { - uint8_t filename; - uint8_t ip; - uint8_t client_id; - uint8_t server_id; -}; struct dhcp_message_reply { uint8_t type; /* Message type */ uint8_t transaction_id[3]; /* Transaction id */ diff --git a/roms/SLOF/clients/net-snk/app/netlib/dns.c b/roms/SLOF/clients/net-snk/app/netlib/dns.c index 0ab1346c9..a5a36a18e 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/dns.c +++ b/roms/SLOF/clients/net-snk/app/netlib/dns.c @@ -133,7 +133,7 @@ dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[16], uint8_t ip_versi * FALSE - error condition occurs. */ int8_t -dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version) +dns_get_ip(int fd, char* url, uint8_t * domain_ip, uint8_t ip_version) { /* this counter is used so that we abort after 30 DNS request */ int32_t i; @@ -143,7 +143,7 @@ dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version) (* domain_ip) = 0; // Retrieve host name from URL - if (!urltohost((char *) url, (char *) host_name)) { + if (!urltohost(url, (char *) host_name)) { printf("\nERROR:\t\t\tBad URL!\n"); return 0; } diff --git a/roms/SLOF/clients/net-snk/app/netlib/dns.h b/roms/SLOF/clients/net-snk/app/netlib/dns.h index 82eea4e4d..b8756afca 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/dns.h +++ b/roms/SLOF/clients/net-snk/app/netlib/dns.h @@ -20,7 +20,7 @@ extern int8_t dns_init(uint32_t _dns_server_ip, uint8_t _dns_server_ipv6[16], uint8_t ip_version); /* For given URL retrieves IPv4 from DNS-server. */ -extern int8_t dns_get_ip(int fd, int8_t * url, uint8_t * domain_ip, uint8_t ip_version); +extern int8_t dns_get_ip(int fd, char * url, uint8_t * domain_ip, uint8_t ip_version); /* Handles DNS-packets, which are detected by receive_ether. */ extern int32_t handle_dns(uint8_t * packet, int32_t packetsize); diff --git a/roms/SLOF/clients/net-snk/app/netlib/ethernet.c b/roms/SLOF/clients/net-snk/app/netlib/ethernet.c index bbfd6d1c3..1e03a0bf3 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/ethernet.c +++ b/roms/SLOF/clients/net-snk/app/netlib/ethernet.c @@ -11,7 +11,7 @@ *****************************************************************************/ -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ +/******************************* ALGORITHMS ******************************/ /** \file netbase.c <pre> * *********************** Receive-handle diagram ************************* @@ -36,12 +36,12 @@ * | APPLICATION +----------------+-----------+ * V | | * upper DNS (handle_dns) BootP / DHCP (handle_bootp_client) - * + * * ************************************************************************ * </pre> */ -/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/ +/************************ DEFINITIONS & DECLARATIONS *********************/ #include <ethernet.h> #include <string.h> @@ -50,22 +50,22 @@ #include <ipv6.h> -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ +/****************************** LOCAL VARIABLES **************************/ static uint8_t ether_packet[ETH_MTU_SIZE]; static uint8_t own_mac[6] = {0, 0, 0, 0, 0, 0}; static uint8_t multicast_mac[] = {0x01, 0x00, 0x5E}; static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/ +/****************************** IMPLEMENTATION ***************************/ /** * Ethernet: Set the own MAC address to initializes ethernet layer. * * @param own_mac own hardware-address (MAC) */ -void -set_mac_address(const uint8_t * _own_mac) { +void set_mac_address(const uint8_t * _own_mac) +{ if (_own_mac) memcpy(own_mac, _own_mac, 6); else @@ -77,19 +77,19 @@ set_mac_address(const uint8_t * _own_mac) { * * @return own hardware-address (MAC) */ -const uint8_t * -get_mac_address(void) { +const uint8_t *get_mac_address(void) +{ return own_mac; } /** * Ethernet: Check if given multicast address is a multicast MAC address - * starting with 0x3333 + * starting with 0x3333 * - * @return true or false + * @return true or false */ -static uint8_t -is_multicast_mac(uint8_t * mac) { +static uint8_t is_multicast_mac(uint8_t * mac) +{ uint16_t mc = 0x3333; if (memcmp(mac, &mc, 2) == 0) @@ -98,7 +98,6 @@ is_multicast_mac(uint8_t * mac) { return 0; } - /** * Ethernet: Receives an ethernet-packet and handles it according to * Receive-handle diagram. @@ -107,8 +106,8 @@ is_multicast_mac(uint8_t * mac) { * @return ZERO - packet was handled or no packets received; * NON ZERO - error condition occurs. */ -int32_t -receive_ether(int fd) { +int32_t receive_ether(int fd) +{ int32_t bytes_received; struct ethhdr * ethh; @@ -118,7 +117,10 @@ receive_ether(int fd) { if (!bytes_received) // No messages return 0; - if (bytes_received < sizeof(struct ethhdr)) + if (bytes_received < 0) + return -1; /* recv() failed */ + + if ((size_t) bytes_received < sizeof(struct ethhdr)) return -1; // packet is too small ethh = (struct ethhdr *) ether_packet; @@ -176,9 +178,9 @@ send_ether(int fd, void* buffer, int len) * @see fill_dnshdr * @see fill_btphdr */ -void -fill_ethhdr(uint8_t * packet, uint16_t eth_type, - const uint8_t * src_mac, const uint8_t * dest_mac) { +void fill_ethhdr(uint8_t * packet, uint16_t eth_type, + const uint8_t * src_mac, const uint8_t * dest_mac) +{ struct ethhdr * ethh = (struct ethhdr *) packet; ethh -> type = htons(eth_type); diff --git a/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c b/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c index be6cc110f..c104f7015 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c +++ b/roms/SLOF/clients/net-snk/app/netlib/icmpv6.c @@ -40,9 +40,8 @@ send_router_solicitation (int fd) sizeof(struct ip6hdr)); /* Destination is "All routers multicast address" (link-local) */ - dest_addr.part.prefix = all_routers_ll.addr.part.prefix; - dest_addr.part.interface_id = all_routers_ll.addr.part.interface_id; - + dest_addr.part.prefix = 0xff02000000000000ULL; + dest_addr.part.interface_id = 2; /* Fill IPv6 header */ fill_ip6hdr (ether_packet + sizeof(struct ethhdr), @@ -78,8 +77,8 @@ handle_prefixoption (uint8_t *option) prefix_option = (struct option_prefix *) option; memcpy( &(prefix.addr), &(prefix_option->prefix.addr), IPV6_ADDR_LENGTH); - /* Link-local adresses in RAs are nonsense */ - if ( (IPV6_LL_PREFIX & (prefix_option->prefix.part.prefix)) == IPV6_LL_PREFIX ) + /* Link-local adresses in RAs are nonsense */ + if (ip6_is_linklocal(&prefix)) return; if (prefix_option->preferred_lifetime > prefix_option->valid_lifetime) diff --git a/roms/SLOF/clients/net-snk/app/netlib/ipv4.c b/roms/SLOF/clients/net-snk/app/netlib/ipv4.c index 8185de5e1..2b92c77c4 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/ipv4.c +++ b/roms/SLOF/clients/net-snk/app/netlib/ipv4.c @@ -11,7 +11,7 @@ *****************************************************************************/ -/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/ +/********************** DEFINITIONS & DECLARATIONS ***********************/ #include <ipv4.h> #include <udp.h> @@ -81,32 +81,26 @@ struct icmphdr { } payload; }; -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ +/****************************** PROTOTYPES *******************************/ -static unsigned short -checksum(unsigned short *packet, int words); +static unsigned short checksum(unsigned short *packet, int words); -static void -arp_send_request(int fd, uint32_t dest_ip); +static void arp_send_request(int fd, uint32_t dest_ip); -static void -arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac); +static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac); -static void -fill_arphdr(uint8_t * packet, uint8_t opcode, - const uint8_t * src_mac, uint32_t src_ip, - const uint8_t * dest_mac, uint32_t dest_ip); +static void fill_arphdr(uint8_t * packet, uint8_t opcode, + const uint8_t * src_mac, uint32_t src_ip, + const uint8_t * dest_mac, uint32_t dest_ip); -static arp_entry_t* -lookup_mac_addr(uint32_t ipv4_addr); +static arp_entry_t *lookup_mac_addr(uint32_t ipv4_addr); -static void -fill_udp_checksum(struct iphdr *ipv4_hdr); +static void fill_udp_checksum(struct iphdr *ipv4_hdr); -static int8_t -handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize); +static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, + int32_t packetsize); -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ +/****************************** LOCAL VARIABLES **************************/ /* Routing parameters */ static uint32_t own_ip = 0; @@ -126,18 +120,19 @@ static uint8_t multicast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static unsigned int arp_consumer = 0; static unsigned int arp_producer = 0; static arp_entry_t arp_table[ARP_ENTRIES]; -static arp_entry_t pending_pkt; + +static uint8_t pending_pkt_frame[ETH_MTU_SIZE]; +static int pending_pkt_len; /* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */ int (*send_ip) (int fd, void *, int); -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/ +/***************************** IMPLEMENTATION ****************************/ /** * IPv4: Initialize the environment for the IPv4 layer. */ -static void -ipv4_init(void) +static void ipv4_init(void) { int i; @@ -153,7 +148,7 @@ ipv4_init(void) arp_table[i].pkt_pending = 0; } - /* Set IP send function to send_ipv4() */ + /* Set IP send function to send_ipv4() */ send_ip = &send_ipv4; } @@ -162,8 +157,7 @@ ipv4_init(void) * * @param _own_ip client IPv4 address (e.g. 127.0.0.1) */ -void -set_ipv4_address(uint32_t _own_ip) +void set_ipv4_address(uint32_t _own_ip) { own_ip = _own_ip; ipv4_init(); @@ -174,8 +168,7 @@ set_ipv4_address(uint32_t _own_ip) * * @return client IPv4 address (e.g. 127.0.0.1) */ -uint32_t -get_ipv4_address(void) +uint32_t get_ipv4_address(void) { return own_ip; } @@ -185,8 +178,7 @@ get_ipv4_address(void) * * @param _own_ip multicast IPv4 address (224.0.0.0 - 239.255.255.255) */ -void -set_ipv4_multicast(uint32_t _multicast_ip) +void set_ipv4_multicast(uint32_t _multicast_ip) { // is this IP Multicast out of range (224.0.0.0 - 239.255.255.255) if((htonl(_multicast_ip) < 0xE0000000) @@ -210,8 +202,7 @@ set_ipv4_multicast(uint32_t _multicast_ip) * * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set) */ -uint32_t -get_ipv4_multicast(void) +uint32_t get_ipv4_multicast(void) { return multicast_ip; } @@ -221,8 +212,7 @@ get_ipv4_multicast(void) * * @param _router_ip router IPv4 address */ -void -set_ipv4_router(uint32_t _router_ip) +void set_ipv4_router(uint32_t _router_ip) { router_ip = _router_ip; ipv4_init(); @@ -233,8 +223,7 @@ set_ipv4_router(uint32_t _router_ip) * * @return router IPv4 address */ -uint32_t -get_ipv4_router(void) +uint32_t get_ipv4_router(void) { return router_ip; } @@ -244,8 +233,7 @@ get_ipv4_router(void) * * @param _subnet_mask netmask of the own IPv4 address */ -void -set_ipv4_netmask(uint32_t _subnet_mask) +void set_ipv4_netmask(uint32_t _subnet_mask) { subnet_mask = _subnet_mask; ipv4_init(); @@ -256,8 +244,7 @@ set_ipv4_netmask(uint32_t _subnet_mask) * * @return netmask of the own IPv4 address */ -uint32_t -get_ipv4_netmask(void) +uint32_t get_ipv4_netmask(void) { return subnet_mask; } @@ -280,9 +267,9 @@ get_ipv4_netmask(void) * @see fill_dnshdr * @see fill_btphdr */ -void -fill_iphdr(uint8_t * packet, uint16_t packetsize, - uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) { +void fill_iphdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) +{ struct iphdr * iph = (struct iphdr *) packet; iph -> ip_hlv = 0x45; @@ -308,8 +295,7 @@ fill_iphdr(uint8_t * packet, uint16_t packetsize, * @see receive_ether * @see iphdr */ -int8_t -handle_ipv4(int fd, uint8_t * ip_packet, int32_t packetsize) +int8_t handle_ipv4(int fd, uint8_t * ip_packet, uint32_t packetsize) { struct iphdr * iph; int32_t old_sum; @@ -422,8 +408,7 @@ handle_ipv4(int fd, uint8_t * ip_packet, int32_t packetsize) * @see receive_ether * @see iphdr */ -int -send_ipv4(int fd, void* buffer, int len) +int send_ipv4(int fd, void* buffer, int len) { arp_entry_t *arp_entry = 0; struct iphdr *ip; @@ -506,13 +491,11 @@ send_ipv4(int fd, void* buffer, int len) arp_entry->pkt_pending = 1; arp_entry->ipv4_addr = ip_dst; memset(arp_entry->mac_addr, 0, 6); - pending_pkt.ipv4_addr = ip_dst; - memset(pending_pkt.mac_addr, 0, 6); - fill_ethhdr (pending_pkt.eth_frame, htons(ETHERTYPE_IP), + fill_ethhdr (pending_pkt_frame, htons(ETHERTYPE_IP), get_mac_address(), null_mac_addr); - memcpy(&pending_pkt.eth_frame[sizeof(struct ethhdr)], + memcpy(&pending_pkt_frame[sizeof(struct ethhdr)], buffer, len); - pending_pkt.eth_len = len + sizeof(struct ethhdr); + pending_pkt_len = len + sizeof(struct ethhdr); set_timer(TICKS_SEC); do { @@ -538,11 +521,9 @@ send_ipv4(int fd, void* buffer, int len) * * @param ipv4_hdr Points to the place where IPv4-header starts. */ - -static void -fill_udp_checksum(struct iphdr *ipv4_hdr) +static void fill_udp_checksum(struct iphdr *ipv4_hdr) { - int i; + unsigned i; unsigned long checksum = 0; struct iphdr ip_hdr; char *ptr; @@ -585,8 +566,7 @@ fill_udp_checksum(struct iphdr *ipv4_hdr) * @return Checksum * @see iphdr */ -static unsigned short -checksum(unsigned short * packet, int words) +static unsigned short checksum(unsigned short * packet, int words) { unsigned long checksum; @@ -598,8 +578,7 @@ checksum(unsigned short * packet, int words) return ~checksum; } -static arp_entry_t* -lookup_mac_addr(uint32_t ipv4_addr) +static arp_entry_t* lookup_mac_addr(uint32_t ipv4_addr) { unsigned int i; @@ -618,8 +597,7 @@ lookup_mac_addr(uint32_t ipv4_addr) * @param fd socket fd * @param dest_ip IP of the host which MAC should be obtained */ -static void -arp_send_request(int fd, uint32_t dest_ip) +static void arp_send_request(int fd, uint32_t dest_ip) { arp_entry_t *arp_entry = &arp_table[arp_producer]; @@ -642,8 +620,7 @@ arp_send_request(int fd, uint32_t dest_ip) * @param src_ip requester IP address (foreign IP) * @param src_mac requester MAC address (foreign MAC) */ -static void -arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac) +static void arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac) { arp_entry_t *arp_entry = &arp_table[arp_producer]; @@ -674,10 +651,9 @@ arp_send_reply(int fd, uint32_t src_ip, uint8_t * src_mac) * @see arphdr * @see fill_ethhdr */ -static void -fill_arphdr(uint8_t * packet, uint8_t opcode, - const uint8_t * src_mac, uint32_t src_ip, - const uint8_t * dest_mac, uint32_t dest_ip) +static void fill_arphdr(uint8_t * packet, uint8_t opcode, + const uint8_t * src_mac, uint32_t src_ip, + const uint8_t * dest_mac, uint32_t dest_ip) { struct arphdr * arph = (struct arphdr *) packet; @@ -706,8 +682,7 @@ fill_arphdr(uint8_t * packet, uint8_t opcode, * @see receive_ether * @see arphdr */ -int8_t -handle_arp(int fd, uint8_t * packet, int32_t packetsize) +int8_t handle_arp(int fd, uint8_t * packet, uint32_t packetsize) { struct arphdr * arph = (struct arphdr *) packet; @@ -754,11 +729,11 @@ handle_arp(int fd, uint8_t * packet, int32_t packetsize) // do we have something to send if (arp_table[i].pkt_pending) { - struct ethhdr * ethh = (struct ethhdr *) pending_pkt.eth_frame; + struct ethhdr * ethh = (struct ethhdr *) pending_pkt_frame; memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6); - send_ether(fd, pending_pkt.eth_frame, pending_pkt.eth_len); - pending_pkt.pkt_pending = 0; + send_ether(fd, pending_pkt_frame, pending_pkt_len); + arp_table[i].pkt_pending = 0; arp_table[i].eth_len = 0; } return 0; // no error @@ -780,8 +755,7 @@ handle_arp(int fd, uint8_t * packet, int32_t packetsize) * @param fd socket descriptor * @param _ping_dst_ip destination IPv4 address */ -void -ping_ipv4(int fd, uint32_t _ping_dst_ip) +void ping_ipv4(int fd, uint32_t _ping_dst_ip) { unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)]; struct icmphdr *icmp; @@ -814,8 +788,7 @@ ping_ipv4(int fd, uint32_t _ping_dst_ip) * * @return ping_dst_ip host IPv4 address */ -uint32_t -pong_ipv4(void) +uint32_t pong_ipv4(void) { return ping_dst_ip; } @@ -830,8 +803,8 @@ pong_ipv4(void) * NON ZERO - packet was not handled (e.g. bad format) * @see handle_ipv4 */ -static int8_t -handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, int32_t packetsize) +static int8_t handle_icmp(int fd, struct iphdr * iph, uint8_t * packet, + int32_t packetsize) { struct icmphdr *icmp = (struct icmphdr *) packet; diff --git a/roms/SLOF/clients/net-snk/app/netlib/ipv4.h b/roms/SLOF/clients/net-snk/app/netlib/ipv4.h index eb719f8b2..18821ea74 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/ipv4.h +++ b/roms/SLOF/clients/net-snk/app/netlib/ipv4.h @@ -60,7 +60,7 @@ struct arphdr { uint32_t dest_ip; /**< Proto address of target of this packet */ } __attribute((packed)); -/*>>>>>>>>>>>>> Initialization of the IPv4 network layer. <<<<<<<<<<<<<*/ +/************** Initialization of the IPv4 network layer. **************/ extern void set_ipv4_address(uint32_t own_ip); extern uint32_t get_ipv4_address(void); extern void set_ipv4_multicast(uint32_t multicast_ip); @@ -88,9 +88,9 @@ extern void ping_ipv4(int fd, uint32_t _ping_dst_ip); extern uint32_t pong_ipv4(void); /* Handles IPv4-packets that are detected by receive_ether. */ -extern int8_t handle_ipv4(int fd, uint8_t * packet, int32_t packetsize); +extern int8_t handle_ipv4(int fd, uint8_t * packet, uint32_t packetsize); /* Handles ARP-packets that are detected by receive_ether. */ -extern int8_t handle_arp(int fd, uint8_t * packet, int32_t packetsize); +extern int8_t handle_arp(int fd, uint8_t * packet, uint32_t packetsize); #endif diff --git a/roms/SLOF/clients/net-snk/app/netlib/ipv6.c b/roms/SLOF/clients/net-snk/app/netlib/ipv6.c index 0cb0a2e7b..62d29ea86 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/ipv6.c +++ b/roms/SLOF/clients/net-snk/app/netlib/ipv6.c @@ -37,15 +37,23 @@ static int ip6_is_multicast (ip6_addr_t * ip); /****************************** LOCAL VARIABLES **************************/ +/* List of Ipv6 Addresses */ +static struct ip6addr_list_entry *first_ip6; +static struct ip6addr_list_entry *last_ip6; + /* Own IPv6 address */ static struct ip6addr_list_entry *own_ip6; +/* All nodes link-local address */ +struct ip6addr_list_entry all_nodes_ll; + /* Null IPv6 address */ static ip6_addr_t null_ip6; /* helper variables */ static uint8_t null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +struct ip6_config ip6_state; /****************************** IMPLEMENTATION ***************************/ @@ -55,9 +63,10 @@ static uint8_t null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; * @param fd Socket descriptor * @param _own_ip client IPv6 address (e.g. ::1) */ -void -set_ipv6_address (int fd, ip6_addr_t *_own_ip6) +void set_ipv6_address(int fd, ip6_addr_t *_own_ip6) { + struct ip6addr_list_entry *ile; + own_ip6 = malloc (sizeof(struct ip6addr_list_entry)); /* If no address was passed as a parameter generate a link-local @@ -73,6 +82,20 @@ set_ipv6_address (int fd, ip6_addr_t *_own_ip6) ip6addr_add (own_ip6); ipv6_init(fd); + + /* + * Check whether we've got a non-link-local address during + * ipv6_init() and use that as preferred address if possible + */ + if (_own_ip6 == NULL) { + for (ile = first_ip6; ile != NULL ; ile = ile->next) { + if (!ip6_is_multicast(&ile->addr) && + !ip6_is_linklocal(&ile->addr)) { + own_ip6 = ile; + break; + } + } + } } /** @@ -80,8 +103,7 @@ set_ipv6_address (int fd, ip6_addr_t *_own_ip6) * * @return pointer to client IPv6 address (e.g. ::1) */ -ip6_addr_t * -get_ipv6_address (void) +ip6_addr_t *get_ipv6_address(void) { return (ip6_addr_t *) &(own_ip6->addr); } @@ -92,8 +114,7 @@ get_ipv6_address (void) * @return 0 - IPv6 address is not in list * 1 - IPv6 address is in list */ -static int8_t -find_ip6addr (ip6_addr_t *ip) +static int8_t find_ip6addr(ip6_addr_t *ip) { struct ip6addr_list_entry *n = NULL; @@ -119,8 +140,7 @@ find_ip6addr (ip6_addr_t *ip) * @see handle_udp * @see ip6hdr */ -int8_t -handle_ipv6 (int fd, uint8_t * ip6_packet, int32_t packetsize) +int8_t handle_ipv6(int fd, uint8_t * ip6_packet, uint32_t packetsize) { struct ip6hdr *ip6 = NULL; @@ -164,11 +184,9 @@ handle_ipv6 (int fd, uint8_t * ip6_packet, int32_t packetsize) * @see fill_dnshdr * @see fill_btphdr */ -void -fill_ip6hdr (uint8_t * packet, uint16_t packetsize, - uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst) +void fill_ip6hdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst) { - struct ip6hdr * ip6h = (struct ip6hdr *) packet; ip6h->ver_tc_fl = 6 << 28; // set version to 6 @@ -184,8 +202,7 @@ fill_ip6hdr (uint8_t * packet, uint16_t packetsize, * See RFC 4291 "IP Version 6 Addressing Architecture" * */ -uint64_t -mac2eui64 (const uint8_t *mac) +uint64_t mac2eui64(const uint8_t *mac) { uint8_t eui64id[8]; uint64_t retid; @@ -205,8 +222,7 @@ mac2eui64 (const uint8_t *mac) * @param own_mac MAC of NIC * @return ll_addr pointer to newly created link-local address */ -ip6_addr_t * -ip6_create_ll_address (const uint8_t *own_mac) +ip6_addr_t *ip6_create_ll_address(const uint8_t *own_mac) { ip6_addr_t *ll_addr; @@ -223,8 +239,7 @@ ip6_create_ll_address (const uint8_t *own_mac) * @param struct ip6_addr_list_entry *ip6 * @return true or false */ -int8_t -unknown_prefix (ip6_addr_t *ip) +int8_t unknown_prefix(ip6_addr_t *ip) { struct ip6addr_list_entry *node; @@ -240,8 +255,7 @@ unknown_prefix (ip6_addr_t *ip) * @return NULL - malloc failed * ! NULL - pointer to new prefix_info */ -struct prefix_info * -ip6_create_prefix_info () +struct prefix_info *ip6_create_prefix_info() { struct prefix_info *prfx_info; @@ -259,8 +273,7 @@ ip6_create_prefix_info () * @param ip6_addr prefix (as received in RA) * @return NULL - pointer to new ip6addr_list entry */ -void * -ip6_prefix2addr (ip6_addr_t prefix) +void *ip6_prefix2addr(ip6_addr_t prefix) { struct ip6addr_list_entry *new_address; uint64_t interface_id; @@ -287,8 +300,7 @@ ip6_prefix2addr (ip6_addr_t prefix) * @return 0 - passed pointer = NULL; * 1 - ok */ -int8_t -ip6addr_add (struct ip6addr_list_entry *new_address) +int8_t ip6addr_add(struct ip6addr_list_entry *new_address) { struct ip6addr_list_entry *solicited_node; @@ -332,8 +344,7 @@ ip6addr_add (struct ip6addr_list_entry *new_address) * * @param fd socket fd */ -static void -ipv6_init (int fd) +static void ipv6_init(int fd) { int i = 0; @@ -349,21 +360,9 @@ ipv6_init (int fd) /* Multicast addresses */ all_nodes_ll.addr.part.prefix = 0xff02000000000000; all_nodes_ll.addr.part.interface_id = 1; - all_dhcpv6_ll.addr.part.prefix = 0xff02000000000000ULL; - all_dhcpv6_ll.addr.part.interface_id = 0x10002ULL; - all_routers_ll.addr.part.prefix = 0xff02000000000000; - all_routers_ll.addr.part.interface_id = 2; - ip6addr_add(&all_nodes_ll); - /* ... */ - /* Router list */ - first_router = NULL; - last_router = first_router; - - /* Init Neighbour cache */ - first_neighbor = NULL; - last_neighbor = first_neighbor; + ndp_init(); send_router_solicitation (fd); for(i=0; i < 4 && !is_ra_received(); i++) { @@ -382,8 +381,7 @@ ipv6_init (int fd) * @param ip6_addr ip_1 * @param ip6_addr ip_2 */ -int8_t -ip6_cmp (ip6_addr_t *ip_1, ip6_addr_t *ip_2) +int8_t ip6_cmp(ip6_addr_t *ip_1, ip6_addr_t *ip_2) { return ((int8_t) !memcmp( &(ip_1->addr[0]), &(ip_2->addr[0]), IPV6_ADDR_LENGTH )); @@ -396,11 +394,9 @@ ip6_cmp (ip6_addr_t *ip_1, ip6_addr_t *ip_2) * @param *ip - pointer to IPv6 address * @return true or false */ -int -ip6_is_multicast (ip6_addr_t * ip) +int ip6_is_multicast(ip6_addr_t * ip) { - uint8_t mc = 0xFF; - return ! memcmp(&ip->addr[0], &mc, 1); + return ip->addr[0] == 0xFF; } /** @@ -408,17 +404,11 @@ ip6_is_multicast (ip6_addr_t * ip) * (e.g. UDP or ICMPv6) * * @param *ip - pointer to IPv6 address + * @param *mc_mac pointer to an array with 6 bytes (for the MAC address) * @return pointer to Multicast MAC address */ -static uint8_t * -ip6_to_multicast_mac (ip6_addr_t * ip) +static uint8_t *ip6_to_multicast_mac(ip6_addr_t * ip, uint8_t *mc_mac) { - uint8_t *mc_mac; - - mc_mac = malloc(ETH_ALEN); - if (!mc_mac) - return NULL; - mc_mac[0] = 0x33; mc_mac[1] = 0x33; memcpy (mc_mac+2, (uint8_t *) &(ip->addr)+12, 4); @@ -437,8 +427,8 @@ ip6_to_multicast_mac (ip6_addr_t * ip) * starting from *packet * @return checksum */ -static unsigned short -ip6_checksum (struct ip6hdr *ip6h, unsigned short *packet, int words) +static unsigned short ip6_checksum(struct ip6hdr *ip6h, unsigned short *packet, + int words) { int i=0; unsigned long checksum; @@ -478,8 +468,7 @@ ip6_checksum (struct ip6hdr *ip6h, unsigned short *packet, int words) * @see receive_ether * @see ip6hdr */ -int -send_ipv6 (int fd, void* buffer, int len) +int send_ipv6(int fd, void* buffer, int len) { struct neighbor *n; struct ip6hdr *ip6h; @@ -519,17 +508,9 @@ send_ipv6 (int fd, void* buffer, int len) n = find_neighbor (&ip_dst); - // If packet is a neighbor solicitation - if (icmp6h->type == ICMPV6_NEIGHBOUR_SOLICITATION) { - mac_addr = ip6_to_multicast_mac (&ip_dst); - fill_ethhdr( buffer-sizeof(struct ethhdr), htons(ETHERTYPE_IPv6), - get_mac_address(), - mac_addr); - } - // If address is a multicast address, create a proper mac address - else if (ip6_is_multicast (&ip_dst)) { - mac_addr = ip6_to_multicast_mac (&ip_dst); + if (ip6_is_multicast (&ip_dst)) { + mac_addr = ip6_to_multicast_mac (&ip_dst, mac); } else { // Check if the MAC address is already cached @@ -572,8 +553,7 @@ send_ipv6 (int fd, void* buffer, int len) return send_ether (fd, n->eth_frame, len + sizeof(struct ethhdr)); } -static int -check_colons(const char *str) +static int check_colons(const char *str) { char *pch, *prv; int col = 0; @@ -595,7 +575,7 @@ check_colons(const char *str) dprintf("The number of col : %d \n",col); dprintf("The number of dcol : %d \n",dcol); - if((dcol > 1) || /* Cannot have 2 "::" */ + if((dcol > 1) || /* Cannot have 2 "::" */ ((dcol == 1) && (col > 5)) || /* Too many ':'s */ ((dcol == 0) && (col != 7)) ) { /* Too few ':'s */ dprintf(" exiting for check_colons \n"); @@ -605,8 +585,7 @@ check_colons(const char *str) return (col+dcol); } -static int -ipv6str_to_bytes(const char *str, char *ip) +static int ipv6str_to_bytes(const char *str, char *ip) { char block[5]; int res; diff --git a/roms/SLOF/clients/net-snk/app/netlib/ipv6.h b/roms/SLOF/clients/net-snk/app/netlib/ipv6.h index b496364f3..72c6ee22f 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/ipv6.h +++ b/roms/SLOF/clients/net-snk/app/netlib/ipv6.h @@ -26,6 +26,7 @@ #define IPV6_ADDR_LENGTH 16 /* Size of IPv6 adress in bytes */ #define IPV6_LL_PREFIX 0xFE80000000000000ULL +#define IPV6_LL_PREFIX_MASK 0xFFC0000000000000ULL #define IPV6_SOLIC_NODE_PREFIX 0xFF02000000000000ULL #define IPV6_SOLIC_NODE_IFACE_ID 0x00000001FF000000ULL @@ -126,32 +127,17 @@ struct ip6_config { uint8_t managed_mode:1, other_config:1, reserved:6; -} ip6_state; +}; /******************** VARIABLES **********************************************/ /* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */ extern int (*send_ip) (int fd, void *, int); -/* IPv6 link-local multicast addresses */ -struct ip6addr_list_entry all_routers_ll; // Routers -struct ip6addr_list_entry all_dhcpv6_ll; // DHCPv6 servers -struct ip6addr_list_entry all_nodes_ll; // All IPv6 nodes - -/* List of Ipv6 Addresses */ -struct ip6addr_list_entry *first_ip6; -struct ip6addr_list_entry *last_ip6; - -/* Neighbor cache */ -struct neighbor *first_neighbor; -struct neighbor *last_neighbor; - -/* Router list */ -struct router *first_router; -struct router *last_router; +extern struct ip6_config ip6_state; /******************** FUNCTIONS *********************************************/ /* Handles IPv6-packets that are detected by receive_ether. */ -int8_t handle_ipv6(int fd, uint8_t * ip6_packet, int32_t packetsize); +int8_t handle_ipv6(int fd, uint8_t * ip6_packet, uint32_t packetsize); /* Fill IPv6 header */ void fill_ip6hdr(uint8_t * packet, uint16_t packetsize, @@ -179,6 +165,12 @@ void * ip6_prefix2addr (ip6_addr_t prefix); /* Compare IPv6 adresses */ int8_t ip6_cmp( ip6_addr_t *ip_1, ip6_addr_t *ip_2 ); +/* Check if it is a link-local address */ +static inline int ip6_is_linklocal(ip6_addr_t *ip) +{ + return (ip->part.prefix & IPV6_LL_PREFIX_MASK) == IPV6_LL_PREFIX; +} + /* Check if prefix is already in our list */ int8_t unknown_prefix (ip6_addr_t *ip); diff --git a/roms/SLOF/clients/net-snk/app/netlib/ndp.c b/roms/SLOF/clients/net-snk/app/netlib/ndp.c index ed9d61f4a..96faa8716 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/ndp.c +++ b/roms/SLOF/clients/net-snk/app/netlib/ndp.c @@ -17,6 +17,14 @@ #include <netlib/icmpv6.h> #include <netlib/ndp.h> +/* Neighbor cache */ +static struct neighbor *first_neighbor; +static struct neighbor *last_neighbor; + +/* Router list */ +static struct router *first_router; +static struct router *last_router; + /* * NET: add new router to list * @param struct router nghb - new router @@ -145,3 +153,14 @@ find_neighbor (ip6_addr_t *ip) return NULL; /* neighbor is unknown */ } + +void ndp_init(void) +{ + /* Router list */ + first_router = NULL; + last_router = first_router; + + /* Init Neighbour cache */ + first_neighbor = NULL; + last_neighbor = first_neighbor; +} diff --git a/roms/SLOF/clients/net-snk/app/netlib/ndp.h b/roms/SLOF/clients/net-snk/app/netlib/ndp.h index ee5235fe1..c785c4897 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/ndp.h +++ b/roms/SLOF/clients/net-snk/app/netlib/ndp.h @@ -59,6 +59,7 @@ struct neighbor { }; /******************** FUNCTIONS *********************************************/ +void ndp_init(void); int8_t neighbor_add (struct neighbor *); void * neighbor_create (uint8_t *packet, struct packeth *headers); struct neighbor * find_neighbor (ip6_addr_t *); diff --git a/roms/SLOF/clients/net-snk/app/netlib/tcp.c b/roms/SLOF/clients/net-snk/app/netlib/tcp.c index 5511aa00a..faa0b83ac 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/tcp.c +++ b/roms/SLOF/clients/net-snk/app/netlib/tcp.c @@ -10,16 +10,14 @@ * IBM Corporation - initial implementation *****************************************************************************/ -/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/ +/************************ DEFINITIONS & DECLARATIONS *********************/ #include <tcp.h> #include <sys/socket.h> +/****************************** LOCAL VARIABLES **************************/ -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ - -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/ - +/****************************** IMPLEMENTATION ***************************/ /** * TCP: Handles TCP-packets according to Receive-handle diagram. @@ -29,13 +27,11 @@ * @return ZERO - packet handled successfully; * NON ZERO - packet was not handled (e.g. bad format) */ -int8_t -handle_tcp(uint8_t * tcp_packet, int32_t packetsize) +int8_t handle_tcp(uint8_t * tcp_packet, int32_t packetsize) { return -1; } - /** * NET: This function handles situation when "Destination unreachable" * ICMP-error occurs during sending TCP-packet. @@ -45,6 +41,6 @@ handle_tcp(uint8_t * tcp_packet, int32_t packetsize) * @param packetsize length of the packet * @see handle_icmp */ -void -handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code) { +void handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code) +{ } diff --git a/roms/SLOF/clients/net-snk/app/netlib/tftp.c b/roms/SLOF/clients/net-snk/app/netlib/tftp.c index 0a7c0ec63..c1197cf17 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/tftp.c +++ b/roms/SLOF/clients/net-snk/app/netlib/tftp.c @@ -50,13 +50,13 @@ static unsigned short block = 0; static unsigned short blocksize; static char blocksize_str[6]; /* Blocksize string for read request */ static int received_len = 0; -static int retries = 0; +static unsigned int retries = 0; static int huge_load; static int len; static int tftp_finished = 0; static int lost_packets = 0; -static int tftp_errno = 0; -static int ip_version = 0; +static int tftp_errno = 0; +static int ip_version = 0; static short port_number = -1; static tftp_err_t *tftp_err; static filename_ip_t *fn_ip; @@ -69,8 +69,7 @@ static filename_ip_t *fn_ip; */ #ifdef __DEBUG__ -static void -dump_package(unsigned char *buffer, unsigned int len) +static void dump_package(unsigned char *buffer, unsigned int len) { int i; @@ -89,8 +88,7 @@ dump_package(unsigned char *buffer, unsigned int len) * * @fd: Socket Descriptor */ -static void -send_rrq(int fd) +static void send_rrq(int fd) { int ip_len = 0; int ip6_payload_len = 0; @@ -121,7 +119,7 @@ send_rrq(int fd) + strlen("blksize") + strlen(blocksize_str) + 2; ip_len = sizeof(struct ip6hdr) + ip6_payload_len; fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(), - &(fn_ip->server_ip6)); + &(fn_ip->server_ip6)); } udp_len = htons(sizeof(struct udphdr) @@ -158,8 +156,7 @@ send_rrq(int fd) * @blckno: block number * @dport: UDP destination port */ -static void -send_ack(int fd, int blckno, unsigned short dport) +static void send_ack(int fd, int blckno, unsigned short dport) { int ip_len = 0; int ip6_payload_len = 0; @@ -182,8 +179,7 @@ send_ack(int fd, int blckno, unsigned short dport) ip6 = (struct ip6hdr *) packet; udph = (struct udphdr *) (ip6 + 1); ip6_payload_len = sizeof(struct udphdr) + 4; - ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) + - ip6_payload_len; + ip_len = sizeof(struct ip6hdr) + ip6_payload_len; fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(), &(fn_ip->server_ip6)); } @@ -210,8 +206,7 @@ send_ack(int fd, int blckno, unsigned short dport) * @error_code: Used sub code for error packet * @dport: UDP destination port */ -static void -send_error(int fd, int error_code, unsigned short dport) +static void send_error(int fd, int error_code, unsigned short dport) { int ip_len = 0; int ip6_payload_len = 0; @@ -234,8 +229,7 @@ send_error(int fd, int error_code, unsigned short dport) ip6 = (struct ip6hdr *) packet; udph = (struct udphdr *) (ip6 + 1); ip6_payload_len = sizeof(struct udphdr) + 5; - ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) + - ip6_payload_len; + ip_len = sizeof(struct ip6hdr) + ip6_payload_len; fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(), &(fn_ip->server_ip6)); } @@ -256,8 +250,7 @@ send_error(int fd, int error_code, unsigned short dport) return; } -static void -print_progress(int urgent, int received_bytes) +static void print_progress(int urgent, int received_bytes) { static unsigned int i = 1; static int first = -1; @@ -265,7 +258,7 @@ print_progress(int urgent, int received_bytes) char buffer[100]; char *ptr; - // 1MB steps or 0x400 times or urgent + // 1MB steps or 0x400 times or urgent if(((received_bytes - last_bytes) >> 20) > 0 || (i & 0x3FF) == 0 || urgent) { if(!first) { @@ -295,8 +288,7 @@ print_progress(int urgent, int received_bytes) * @param len the length of the network packet * @return the blocksize the server supports or 0 for error */ -static int -get_blksize(unsigned char *buffer, unsigned int len) +static int get_blksize(unsigned char *buffer, unsigned int len) { unsigned char *orig = buffer; /* skip all headers until tftp has been reached */ @@ -325,7 +317,7 @@ get_blksize(unsigned char *buffer, unsigned int len) } /** - * Handle incoming tftp packets after read request was sent + * Handle incoming tftp packets after read request was sent * * this function also prints out some status characters * \|-/ for each packet received @@ -334,13 +326,12 @@ get_blksize(unsigned char *buffer, unsigned int len) * #+* for different unexpected TFTP packets (not very good) * * @param fd socket descriptor - * @param packet points to the UDP header of the packet + * @param packet points to the UDP header of the packet * @param len the length of the network packet * @return ZERO if packet was handled successfully - * ERRORCODE if error occurred + * ERRORCODE if error occurred */ -int32_t -handle_tftp(int fd, uint8_t *pkt, int32_t packetsize) +int32_t handle_tftp(int fd, uint8_t *pkt, int32_t packetsize) { struct udphdr *udph; struct tftphdr *tftp; @@ -397,7 +388,7 @@ handle_tftp(int fd, uint8_t *pkt, int32_t packetsize) case ENOUSER: tftp_errno = -7; // ERROR: no such user break; - default: + default: tftp_errno = -1; // ERROR: unknown error } goto error; @@ -489,8 +480,7 @@ error: * * @param err_code Error Code (e.g. "Host unreachable") */ -void -handle_tftp_dun(uint8_t err_code) +void handle_tftp_dun(uint8_t err_code) { tftp_errno = - err_code - 10; tftp_finished = 1; @@ -510,10 +500,9 @@ handle_tftp_dun(uint8_t err_code) * @return ZERO - error condition occurs * NON ZERO - size of received file */ -int -tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len, - unsigned int _retries, tftp_err_t * _tftp_err, - int32_t _mode, int32_t _blocksize, int _ip_version) +int tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len, + unsigned int _retries, tftp_err_t * _tftp_err, + int32_t _mode, int32_t _blocksize, int _ip_version) { retries = _retries; fn_ip = _fn_ip; @@ -592,6 +581,6 @@ tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len, printf("\n"); if (lost_packets) printf("Lost ACK packets: %d\n", lost_packets); - + return received_len; } diff --git a/roms/SLOF/clients/net-snk/app/netlib/udp.c b/roms/SLOF/clients/net-snk/app/netlib/udp.c index db29bc90f..5d16e52c6 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/udp.c +++ b/roms/SLOF/clients/net-snk/app/netlib/udp.c @@ -10,7 +10,7 @@ * IBM Corporation - initial implementation *****************************************************************************/ -/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/ +/************************ DEFINITIONS & DECLARATIONS *********************/ #include <udp.h> #include <sys/socket.h> @@ -25,7 +25,7 @@ -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ +/****************************** LOCAL VARIABLES **************************/ #ifdef USE_MTFTP @@ -33,17 +33,19 @@ uint16_t net_tftp_uport; uint16_t net_mtftp_uport; -void net_set_tftp_port(uint16_t tftp_port) { +void net_set_tftp_port(uint16_t tftp_port) +{ net_tftp_uport = tftp_port; } -void net_set_mtftp_port(uint16_t tftp_port) { +void net_set_mtftp_port(uint16_t tftp_port) +{ net_mtftp_uport = tftp_port; } #endif -/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/ +/****************************** IMPLEMENTATION ***************************/ /** @@ -56,8 +58,8 @@ void net_set_mtftp_port(uint16_t tftp_port) { * @see receive_ether * @see udphdr */ -int8_t -handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize) { +int8_t handle_udp(int fd, uint8_t * udp_packet, uint32_t packetsize) +{ struct udphdr * udph = (struct udphdr *) udp_packet; if (packetsize < sizeof(struct udphdr)) @@ -108,8 +110,8 @@ handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize) { * @param packetsize length of the packet * @see handle_icmp */ -void -handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code) { +void handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code) +{ struct udphdr * udph = (struct udphdr *) udp_packet; if (packetsize < sizeof(struct udphdr)) @@ -139,9 +141,9 @@ handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code) { * @see fill_dnshdr * @see fill_btphdr */ -void -fill_udphdr(uint8_t * packet, uint16_t packetsize, - uint16_t src_port, uint16_t dest_port) { +void fill_udphdr(uint8_t * packet, uint16_t packetsize, + uint16_t src_port, uint16_t dest_port) +{ struct udphdr * udph = (struct udphdr *) packet; udph -> uh_sport = htons(src_port); diff --git a/roms/SLOF/clients/net-snk/app/netlib/udp.h b/roms/SLOF/clients/net-snk/app/netlib/udp.h index 1ba9332ce..f154542dd 100644 --- a/roms/SLOF/clients/net-snk/app/netlib/udp.h +++ b/roms/SLOF/clients/net-snk/app/netlib/udp.h @@ -40,7 +40,7 @@ typedef int32_t *(*handle_upper_udp_t)(uint8_t *, int32_t); typedef void *(*handle_upper_udp_dun_t)(uint8_t); /* Handles UDP-packets that are detected by any network layer. */ -extern int8_t handle_udp(int fd, uint8_t * udp_packet, int32_t packetsize); +extern int8_t handle_udp(int fd, uint8_t * udp_packet, uint32_t packetsize); /* Handles UDP related ICMP-Dest.Unreachable packets that are detected by * the network layers. */ diff --git a/roms/SLOF/include/byteorder.h b/roms/SLOF/include/byteorder.h index 60ca67267..d4a2c8ca7 100644 --- a/roms/SLOF/include/byteorder.h +++ b/roms/SLOF/include/byteorder.h @@ -19,38 +19,36 @@ #include <stdint.h> -static inline uint16_t -bswap_16 (uint16_t x) +typedef uint16_t le16; +typedef uint32_t le32; +typedef uint64_t le64; + +static inline uint16_t bswap_16 (uint16_t x) { return __builtin_bswap16(x); } -static inline uint32_t -bswap_32 (uint32_t x) +static inline uint32_t bswap_32 (uint32_t x) { return __builtin_bswap32(x); } -static inline uint64_t -bswap_64 (uint64_t x) +static inline uint64_t bswap_64 (uint64_t x) { return __builtin_bswap64(x); } -static inline void -bswap_16p (uint16_t *x) +static inline void bswap_16p (uint16_t *x) { *x = __builtin_bswap16(*x); } -static inline void -bswap_32p (uint32_t *x) +static inline void bswap_32p (uint32_t *x) { *x = __builtin_bswap32(*x); } -static inline void -bswap_64p (uint64_t *x) +static inline void bswap_64p (uint64_t *x) { *x = __builtin_bswap64(*x); } diff --git a/roms/SLOF/include/helpers.h b/roms/SLOF/include/helpers.h index fb105345e..5b3d711ac 100644 --- a/roms/SLOF/include/helpers.h +++ b/roms/SLOF/include/helpers.h @@ -30,8 +30,10 @@ extern long SLOF_dma_map_in(void *virt, long size, int cacheable); extern void SLOF_dma_map_out(long phys, void *virt, long size); extern long SLOF_pci_config_read32(long offset); extern long SLOF_pci_config_read16(long offset); +extern long SLOF_pci_config_read8(long offset); extern void SLOF_pci_config_write32(long offset, long value); extern void SLOF_pci_config_write16(long offset, long value); +extern void SLOF_pci_config_write8(long offset, long value); extern void *SLOF_translate_my_address(void *addr); #define offset_of(type, member) ((long) &((type *)0)->member) diff --git a/roms/SLOF/include/ppcp7/cache.h b/roms/SLOF/include/ppcp7/cache.h index 27975f09c..3c02bb10d 100644 --- a/roms/SLOF/include/ppcp7/cache.h +++ b/roms/SLOF/include/ppcp7/cache.h @@ -124,17 +124,8 @@ static inline void ci_rmove(void *dst, void *src, unsigned long esize, #define FAST_MRMOVE(s, d, size) _FASTRMOVE(s, d, size) -#define FAST_RFILL(dst, size, pat) do { \ - type_u buf[64]; \ - char *d = (char *)(dst); \ - memset(buf, pat, size < sizeof(buf) ? size : sizeof(buf)); \ - while (size > sizeof(buf)) { \ - FAST_MRMOVE(buf, d, sizeof(buf)); \ - d += sizeof(buf); \ - size -= sizeof(buf); \ - } \ - FAST_MRMOVE(buf, d, size); \ - } while(0) +extern void fast_rfill(char *dst, long size, char pat); +#define FAST_RFILL(dst, size, pat) fast_rfill(dst, size, pat) static inline uint16_t bswap16_load(uint64_t addr) { diff --git a/roms/SLOF/lib/libc/include/stdlib.h b/roms/SLOF/lib/libc/include/stdlib.h index dff57f577..5e0eda9ff 100644 --- a/roms/SLOF/lib/libc/include/stdlib.h +++ b/roms/SLOF/lib/libc/include/stdlib.h @@ -29,5 +29,6 @@ unsigned long int strtoul(const char *nptr, char **endptr, int base); long int strtol(const char *nptr, char **endptr, int base); int rand(void); +void srand(unsigned int seed); #endif diff --git a/roms/SLOF/lib/libc/stdio/vsnprintf.c b/roms/SLOF/lib/libc/stdio/vsnprintf.c index e78fb3d8e..21dd04dfe 100644 --- a/roms/SLOF/lib/libc/stdio/vsnprintf.c +++ b/roms/SLOF/lib/libc/stdio/vsnprintf.c @@ -10,72 +10,110 @@ * IBM Corporation - initial implementation *****************************************************************************/ +#include <stdbool.h> #include "stdio.h" #include "stdlib.h" #include "string.h" +#include "ctype.h" -const static unsigned long long convert[] = { +static const unsigned long long convert[] = { 0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF, 0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL }; - - static int -print_itoa(char **buffer,unsigned long value, unsigned short int base) +print_str_fill(char **buffer, size_t bufsize, char *sizec, + const char *str, char c) { - const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; - static char sign = 0; - - if(base <= 2 || base > 16) - return 0; - - if(value < 0) { - sign = 1; - value *= -1; - } + int i, sizei, len; + char *bstart = *buffer; - if(value < base) { - if(sign) { - **buffer = '-'; + sizei = strtoul(sizec, NULL, 10); + len = strlen(str); + if (sizei > len) { + for (i = 0; + (i < (sizei - len)) && ((*buffer - bstart) < bufsize); + i++) { + **buffer = c; *buffer += 1; - sign = 0; } - **buffer = zeichen[value]; - *buffer += 1; - } else { - print_itoa(buffer, value / base, base); - **buffer = zeichen[(value % base)]; - *buffer += 1; } - return 1; } +static int +print_str(char **buffer, size_t bufsize, const char *str) +{ + char *bstart = *buffer; + size_t i; + + for (i = 0; (i < strlen(str)) && ((*buffer - bstart) < bufsize); i++) { + **buffer = str[i]; + *buffer += 1; + } + return 1; +} static unsigned int print_intlen(unsigned long value, unsigned short int base) { int i = 0; - while(value > 0) { + while (value > 0) { value /= base; i++; } - if(i == 0) i = 1; + if (i == 0) + i = 1; return i; } +static int +print_itoa(char **buffer, size_t bufsize, unsigned long value, + unsigned short base, bool upper) +{ + const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + char c; + size_t i, len; + + if(base <= 2 || base > 16) + return 0; + + len = i = print_intlen(value, base); + + /* Don't print to buffer if bufsize is not enough. */ + if (len > bufsize) + return 0; + + do { + c = zeichen[value % base]; + if (upper) + c = toupper(c); + + (*buffer)[--i] = c; + value /= base; + } while(value); + + *buffer += len; + + return 1; +} + + static int -print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int base, char c, int optlen) +print_fill(char **buffer, size_t bufsize, char *sizec, unsigned long size, + unsigned short int base, char c, int optlen) { int i, sizei, len; + char *bstart = *buffer; sizei = strtoul(sizec, NULL, 10); len = print_intlen(size, base) + optlen; - if(sizei > len) { - for(i = 0; i < (sizei - len); i++) { + if (sizei > len) { + for (i = 0; + (i < (sizei - len)) && ((*buffer - bstart) < bufsize); + i++) { **buffer = c; *buffer += 1; } @@ -86,17 +124,18 @@ print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int ba static int -print_format(char **buffer, const char *format, void *var) +print_format(char **buffer, size_t bufsize, const char *format, void *var) { - unsigned long start; - unsigned int i = 0, sizei = 0, len = 0, length_mod = sizeof(int); + char *start; + unsigned int i = 0, length_mod = sizeof(int); unsigned long value = 0; unsigned long signBit; char *form, sizec[32]; char sign = ' '; + bool upper = false; form = (char *) format; - start = (unsigned long) *buffer; + start = *buffer; form++; if(*form == '0' || *form == '.') { @@ -104,7 +143,7 @@ print_format(char **buffer, const char *format, void *var) form++; } - while(*form != '\0') { + while ((*form != '\0') && ((*buffer - start) < bufsize)) { switch(*form) { case 'u': case 'd': @@ -112,57 +151,59 @@ print_format(char **buffer, const char *format, void *var) sizec[i] = '\0'; value = (unsigned long) var; signBit = 0x1ULL << (length_mod * 8 - 1); - if (signBit & value) { + if ((*form != 'u') && (signBit & value)) { **buffer = '-'; *buffer += 1; value = (-(unsigned long)value) & convert[length_mod]; } - print_fill(buffer, sizec, value, 10, sign, 0); - print_itoa(buffer, value, 10); + print_fill(buffer, bufsize - (*buffer - start), + sizec, value, 10, sign, 0); + print_itoa(buffer, bufsize - (*buffer - start), + value, 10, upper); break; case 'X': + upper = true; case 'x': sizec[i] = '\0'; value = (unsigned long) var & convert[length_mod]; - print_fill(buffer, sizec, value, 16, sign, 0); - print_itoa(buffer, value, 16); + print_fill(buffer, bufsize - (*buffer - start), + sizec, value, 16, sign, 0); + print_itoa(buffer, bufsize - (*buffer - start), + value, 16, upper); break; case 'O': case 'o': sizec[i] = '\0'; value = (long int) var & convert[length_mod]; - print_fill(buffer, sizec, value, 8, sign, 0); - print_itoa(buffer, value, 8); + print_fill(buffer, bufsize - (*buffer - start), + sizec, value, 8, sign, 0); + print_itoa(buffer, bufsize - (*buffer - start), + value, 8, upper); break; case 'p': sizec[i] = '\0'; - print_fill(buffer, sizec, (unsigned long) var, 16, ' ', 2); - **buffer = '0'; - *buffer += 1; - **buffer = 'x'; - *buffer += 1; - print_itoa(buffer,(unsigned long) var, 16); + print_fill(buffer, bufsize - (*buffer - start), + sizec, (unsigned long) var, 16, ' ', 2); + print_str(buffer, bufsize - (*buffer - start), + "0x"); + print_itoa(buffer, bufsize - (*buffer - start), + (unsigned long) var, 16, upper); break; case 'c': sizec[i] = '\0'; - print_fill(buffer, sizec, 1, 10, ' ', 0); + print_fill(buffer, bufsize - (*buffer - start), + sizec, 1, 10, ' ', 0); **buffer = (unsigned long) var; *buffer += 1; break; case 's': sizec[i] = '\0'; - sizei = strtoul(sizec, NULL, 10); - len = strlen((char *) var); - if(sizei > len) { - for(i = 0; i < (sizei - len); i++) { - **buffer = ' '; - *buffer += 1; - } - } - for(i = 0; i < strlen((char *) var); i++) { - **buffer = ((char *) var)[i]; - *buffer += 1; - } + print_str_fill(buffer, + bufsize - (*buffer - start), sizec, + (char *) var, ' '); + + print_str(buffer, bufsize - (*buffer - start), + (char *) var); break; case 'l': form++; @@ -182,6 +223,9 @@ print_format(char **buffer, const char *format, void *var) length_mod = sizeof(short int); } break; + case 'z': + length_mod = sizeof(size_t); + break; default: if(*form >= '0' && *form <= '9') sizec[i++] = *form; @@ -206,6 +250,16 @@ vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg) bstart = buffer; ptr = (char *) format; + /* + * Return from here if size passed is zero, otherwise we would + * overrun buffer while setting NULL character at the end. + */ + if (!buffer || !bufsize) + return 0; + + /* Leave one space for NULL character */ + bufsize--; + while(*ptr != '\0' && (buffer - bstart) < bufsize) { if(*ptr == '%') { @@ -224,7 +278,9 @@ vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg) if(*ptr == '%') { *buffer++ = '%'; } else { - print_format(&buffer, formstr, va_arg(arg, void *)); + print_format(&buffer, + bufsize - (buffer - bstart), + formstr, va_arg(arg, void *)); } ptr++; } else { diff --git a/roms/SLOF/lib/libc/stdlib/rand.c b/roms/SLOF/lib/libc/stdlib/rand.c index 87e3efd29..39f5a9a2c 100644 --- a/roms/SLOF/lib/libc/stdlib/rand.c +++ b/roms/SLOF/lib/libc/stdlib/rand.c @@ -18,7 +18,12 @@ static unsigned long _rand = 1; int rand(void) { - _rand = _rand * 25364735 + 34563; + _rand = _rand * 1237732973 + 34563; - return ((unsigned int) (_rand << 16) & RAND_MAX); + return ((unsigned int) (_rand >> 16) & RAND_MAX); +} + +void srand(unsigned int seed) +{ + _rand = seed; } diff --git a/roms/SLOF/lib/libhvcall/Makefile b/roms/SLOF/lib/libhvcall/Makefile index 2a9b2d7d1..def532509 100644 --- a/roms/SLOF/lib/libhvcall/Makefile +++ b/roms/SLOF/lib/libhvcall/Makefile @@ -24,7 +24,7 @@ TARGET = ../libhvcall.a all: $(TARGET) -SRCS = brokensc1.c +SRCS = brokensc1.c rfill.c SRCSS = hvcall.S diff --git a/roms/SLOF/lib/libhvcall/rfill.c b/roms/SLOF/lib/libhvcall/rfill.c new file mode 100644 index 000000000..5407cd2a6 --- /dev/null +++ b/roms/SLOF/lib/libhvcall/rfill.c @@ -0,0 +1,38 @@ +/***************************************************************************** + * Fast function for filling cache-inhibited memory regions via h-call. + * + * Copyright 2015 Red Hat, Inc. + * + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * Thomas Huth, Red Hat Inc. - initial implementation + *****************************************************************************/ + +#include <cache.h> +#include <string.h> + +typedef unsigned long type_u; + +/** + * fast_rfill is the implementation of the FAST_RFILL macro with h-calls. + * This is defined here instead of cache.h since we need a temporary + * local buffer - and that caused stack size problems in engine() when + * we used it directly in the FAST_RFILL macro. + */ +void fast_rfill(char *dst, long size, char pat) +{ + type_u buf[64]; + + memset(buf, pat, size < sizeof(buf) ? size : sizeof(buf)); + + while (size > sizeof(buf)) { + FAST_MRMOVE(buf, dst, sizeof(buf)); + dst += sizeof(buf); + size -= sizeof(buf); + } + FAST_MRMOVE(buf, dst, size); +} diff --git a/roms/SLOF/lib/libnvram/envvar.c b/roms/SLOF/lib/libnvram/envvar.c index 87aaf27a0..ee943fce5 100644 --- a/roms/SLOF/lib/libnvram/envvar.c +++ b/roms/SLOF/lib/libnvram/envvar.c @@ -17,7 +17,7 @@ #include "nvram.h" /* returns the offset of the first byte after the searched envvar */ -static int get_past_env_pos(partition_t part, char *envvar) +static int get_past_env_pos(partition_t part, char *envvar, int evlen) { int offset, len; static char temp[256]; @@ -32,7 +32,7 @@ static int get_past_env_pos(partition_t part, char *envvar) while((data=nvram_read_byte(offset++)) && len < 256) { temp[len++]=data; } - if (!strncmp(envvar, temp, strlen(envvar))) { + if (!strncmp(envvar, temp, evlen)) { return offset; } } while (len); @@ -43,16 +43,16 @@ static int get_past_env_pos(partition_t part, char *envvar) /** * @param partition name of the envvar partition * @param envvar name of the environment variable + * @param evlen string length of the envvar parameter * @return pointer to temporary string containing the value of envvar */ - -char *get_env(partition_t part, char *envvar) +char *nvram_get_env(partition_t part, char *envvar, int evlen) { static char temp[256+1]; int len, offset; uint8_t data; - DEBUG("get_env %s... ", envvar); + DEBUG("nvram_get_env %p... ", envvar); if(!part.addr) { /* ERROR: No environment variable partition */ DEBUG("invalid partition.\n"); @@ -68,7 +68,7 @@ char *get_env(partition_t part, char *envvar) } temp[len]=0; - if (!strncmp(envvar, temp, strlen(envvar))) { + if (!strncmp(envvar, temp, evlen)) { int pos=0; while (temp[pos]!='=' && pos < len) pos++; // DEBUG("value='%s'\n", temp+pos+1); @@ -100,7 +100,7 @@ static int find_last_envvar(partition_t part) return -1; } -int add_env(partition_t part, char *envvar, char *value) +int nvram_add_env(partition_t part, char *envvar, int evlen, char *value, int vallen) { int freespace, last, len, offset; unsigned int i; @@ -112,7 +112,7 @@ int add_env(partition_t part, char *envvar, char *value) freespace = part.addr+part.len-last; /* how long is the entry we want to write? */ - len = strlen(envvar) + strlen(value) + 2; + len = evlen + vallen + 2; if(freespace<len) { // TODO try to increase partition size @@ -121,18 +121,18 @@ int add_env(partition_t part, char *envvar, char *value) offset=last; - for(i=0; i<strlen(envvar); i++) + for (i = 0; i < evlen; i++) nvram_write_byte(offset++, envvar[i]); nvram_write_byte(offset++, '='); - for(i=0; i<strlen(value); i++) + for (i = 0; i < vallen; i++) nvram_write_byte(offset++, value[i]); return 0; } -int del_env(partition_t part, char *envvar) +int nvram_del_env(partition_t part, char *envvar, int evlen) { int last, current, pos, i; char *buffer; @@ -141,7 +141,7 @@ int del_env(partition_t part, char *envvar) return -1; last=find_last_envvar(part); - current = pos = get_past_env_pos(part, envvar); + current = pos = get_past_env_pos(part, envvar, evlen); // TODO is this really required? /* go back to non-0 value */ @@ -168,25 +168,25 @@ int del_env(partition_t part, char *envvar) return 0; } -int set_env(partition_t part, char *envvar, char *value) +int nvram_set_env(partition_t part, char *envvar, int evlen, char *value, int vallen) { char *oldvalue, *buffer; int last, current, buffersize, i; - DEBUG("set_env %lx[%lx]: %s=%s\n", part.addr, part.len, envvar, value); + DEBUG("nvram_set_env %lx[%lx]: %p=>%p\n", part.addr, part.len, envvar, value); if(!part.addr) return -1; /* Check whether the environment variable exists already */ - oldvalue = get_env(part, envvar); + oldvalue = nvram_get_env(part, envvar, evlen); - if(oldvalue==NULL) - return add_env(part, envvar, value); + if (oldvalue == NULL) + return nvram_add_env(part, envvar, evlen, value, vallen); /* The value did not change. So we succeeded! */ - if(!strncmp(oldvalue, value, strlen(value)+1)) + if (strlen(oldvalue) == vallen && !strncmp(oldvalue, value, vallen)) return 0; /* we need to overwrite environment variables, back them up first */ @@ -195,7 +195,7 @@ int set_env(partition_t part, char *envvar, char *value) /* allocate a buffer */ last=find_last_envvar(part); - current=get_past_env_pos(part, envvar); + current = get_past_env_pos(part, envvar, evlen); buffersize = last - current; buffer=get_nvram_buffer(buffersize); if(!buffer) @@ -214,7 +214,7 @@ int set_env(partition_t part, char *envvar, char *value) current++; /* Write the new value */ - for(i=0; i<(int)strlen(value); i++) { + for(i = 0; i < vallen; i++) { nvram_write_byte(current++, value[i]); } diff --git a/roms/SLOF/lib/libnvram/libnvram.code b/roms/SLOF/lib/libnvram/libnvram.code index 723941d3e..8481f57f5 100644 --- a/roms/SLOF/lib/libnvram/libnvram.code +++ b/roms/SLOF/lib/libnvram/libnvram.code @@ -11,17 +11,6 @@ *****************************************************************************/ #include <nvram.h> -#define STRING_INIT(str) \ - char str[255]; \ - char * str##_address; \ - int str##_length; - -#define STRING_FROM_STACK(str) \ - str##_length = TOS.u; POP; \ - str##_address = TOS.a; POP; \ - memcpy(str, str##_address, str##_length); \ - memset(str + str##_length, 0, 255 - str##_length); - PRIM(nvram_X2d_c_X40) unsigned int offset = TOS.u; TOS.u=nvram_read_byte(offset); @@ -80,21 +69,18 @@ MIRP /* get-named-nvram-partition ( name.addr name.len -- addr len FAILED? ) */ PRIM(get_X2d_named_X2d_nvram_X2d_partition) - STRING_INIT(name) partition_t partition; + int namelen = TOS.n; POP; - STRING_FROM_STACK(name) - partition = get_partition(-1, name); + partition = get_partition_fs(TOS.a, namelen); if(partition.len && partition.len != -1) { - PUSH; TOS.u = partition.addr; PUSH; TOS.u = partition.len; PUSH; TOS.u = 0; // FALSE } else { - PUSH; TOS.u = -1; // TRUE } MIRP @@ -103,23 +89,16 @@ MIRP /* new-nvram-partition ( type name.addr name.len len -- part.offs part.len FALSE | TRUE) */ PRIM(new_X2d_nvram_X2d_partition) - int type, len, i, slen; - char name[12], *addr; + int type, len, namelen; partition_t partition; + char *name; len = TOS.u; POP; - slen = TOS.u; POP; - addr = (char *)TOS.u; POP; + namelen = TOS.u; POP; + name = (char *)TOS.u; POP; type = TOS.u; POP; - for (i=0; i<12; i++) { - if(slen>i) - name[i]=addr[i]; - else - name[i]=0; - } - - partition=new_nvram_partition(type, name, len); + partition = new_nvram_partition_fs(type, name, namelen, len); if(!partition.len) { PUSH; TOS.u = -1; // TRUE @@ -165,15 +144,17 @@ MIRP // ( part.start part.len name.addr name.len -- var.addr var.len TRUE | false ) PRIM(internal_X2d_get_X2d_env) - STRING_INIT(name) + char *name; + int namelen; partition_t part; char *val; - STRING_FROM_STACK(name) + namelen = TOS.u; POP; + name = TOS.a; POP; part.len = TOS.u; POP; part.addr = TOS.u; POP; - val=get_env(part, name); + val = nvram_get_env(part, name, namelen); if(val) { PUSH; TOS.a = val; PUSH; TOS.u = strlen(val); @@ -185,17 +166,19 @@ MIRP // ( part.start part.len name.addr name.len val.addr val.len -- FALSE|TRUE) PRIM(internal_X2d_add_X2d_env) - STRING_INIT(name) - STRING_INIT(value) + char *name, *val; + int namelen, vallen; partition_t part; int ret; - STRING_FROM_STACK(value) - STRING_FROM_STACK(name) + vallen = TOS.u; POP; + val = TOS.a; POP; + namelen = TOS.u; POP; + name = TOS.a; POP; part.len = TOS.u; POP; part.addr = TOS.u; POP; - ret=add_env(part, name, value); + ret = nvram_add_env(part, name, namelen, val, vallen); if(ret) { PUSH; TOS.u = -1; // TRUE } else { @@ -205,15 +188,17 @@ MIRP // ( part.addr part.len name.addr name.len -- FALSE|TRUE) PRIM(internal_X2d_del_X2d_env) - STRING_INIT(name) + char *name; + int namelen; partition_t part; int ret; - STRING_FROM_STACK(name); + namelen = TOS.u; POP; + name = TOS.a; POP; part.len = TOS.u; POP; part.addr = TOS.u; POP; - ret=del_env(part, name); + ret = nvram_del_env(part, name, namelen); if(ret) { PUSH; TOS.u = -1; // TRUE } else { @@ -224,17 +209,19 @@ MIRP // internal-set-env ( part.addr part.len name.addr name.len val.addr val.len -- FALSE|TRUE) PRIM(internal_X2d_set_X2d_env) - STRING_INIT(name) - STRING_INIT(value) + char *name, *value; + int namelen, valuelen; partition_t part; int ret; - STRING_FROM_STACK(value) - STRING_FROM_STACK(name) + valuelen = TOS.u; POP; + value = TOS.a; POP; + namelen = TOS.u; POP; + name = TOS.a; POP; part.len = TOS.u; POP; part.addr = TOS.u; POP; - ret=set_env(part, name, value); + ret = nvram_set_env(part, name, namelen, value, valuelen); if(ret) { PUSH; TOS.u = -1; // TRUE } else { diff --git a/roms/SLOF/lib/libnvram/nvram.c b/roms/SLOF/lib/libnvram/nvram.c index 5c1137669..473814e5c 100644 --- a/roms/SLOF/lib/libnvram/nvram.c +++ b/roms/SLOF/lib/libnvram/nvram.c @@ -358,6 +358,17 @@ partition_t get_partition(unsigned int type, char *name) return ret; } +/* Get partition specified by a Forth string */ +partition_t get_partition_fs(char *name, int namelen) +{ + char buf[namelen + 1]; + + memcpy(buf, name, namelen); + buf[namelen] = 0; + + return get_partition(-1, buf); +} + void erase_nvram(int offset, int len) { int i; @@ -466,6 +477,22 @@ partition_t new_nvram_partition(int type, char *name, int len) return new_part; } +partition_t new_nvram_partition_fs(int type, char *name, int namelen, int len) +{ + char buf[13]; + int i; + + for (i = 0; i < 12; i++) { + if (i < namelen) + buf[i] = name[i]; + else + buf[i] = 0; + } + buf[12] = 0; + + return new_nvram_partition(type, buf, len); +} + /** * @param partition partition structure pointing to the partition to wipe. */ diff --git a/roms/SLOF/lib/libnvram/nvram.h b/roms/SLOF/lib/libnvram/nvram.h index fa6bdd425..73fe44424 100644 --- a/roms/SLOF/lib/libnvram/nvram.h +++ b/roms/SLOF/lib/libnvram/nvram.h @@ -51,9 +51,11 @@ char *get_nvram_buffer(int len); void free_nvram_buffer(char *buffer); int nvramlog_printf(const char* fmt, ...); partition_t get_partition(unsigned int type, char *name); +partition_t get_partition_fs(char *name, int namelen); void erase_nvram(int offset, int len); int wipe_partition(partition_t partition, int header_only); partition_t new_nvram_partition(int type, char *name, int len); +partition_t new_nvram_partition_fs(int type, char *name, int namelen, int len); int increase_nvram_partition_size(partition_t partition, int newsize); int clear_nvram_partition(partition_t part); int delete_nvram_partition(partition_t part); @@ -65,9 +67,9 @@ void nvram_init(uint32_t store_token, uint32_t fetch_token, unsigned int get_nvram_size(void); /* envvar.c */ -char *get_env(partition_t part, char *envvar); -int add_env(partition_t part, char *envvar, char *value); -int del_env(partition_t part, char *envvar); -int set_env(partition_t part, char *envvar, char *value); +char *nvram_get_env(partition_t part, char *envvar, int evlen); +int nvram_add_env(partition_t part, char *envvar, int evlen, char *value, int vallen); +int nvram_del_env(partition_t part, char *envvar, int evlen); +int nvram_set_env(partition_t part, char *envvar, int evlen, char *val, int vlen); #endif diff --git a/roms/SLOF/lib/libusb/usb-core.c b/roms/SLOF/lib/libusb/usb-core.c index 6719c5726..4c720ce2f 100644 --- a/roms/SLOF/lib/libusb/usb-core.c +++ b/roms/SLOF/lib/libusb/usb-core.c @@ -383,8 +383,6 @@ int usb_hid_exit(void *vdev) return true; } -#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16) - int usb_msc_init(void *vdev) { struct usb_dev *dev; @@ -420,7 +418,7 @@ int usb_msc_exit(void *vdev) return true; } -static int usb_msc_reset(struct usb_dev *dev) +int usb_msc_reset(struct usb_dev *dev) { struct usb_dev_req req; @@ -477,7 +475,7 @@ static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *c case DESCR_TYPE_HUB: break; default: - printf("ptr %p desc_type %d\n", ptr, desc_type); + dprintf("ptr %p desc_type %d\n", ptr, desc_type); } ptr += desc_len; len -= desc_len; @@ -485,7 +483,7 @@ static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *c return true; } -int setup_new_device(struct usb_dev *dev, unsigned int port) +int usb_setup_new_device(struct usb_dev *dev, unsigned int port) { struct usb_dev_descr descr; struct usb_dev_config_descr cfg; @@ -552,35 +550,6 @@ int setup_new_device(struct usb_dev *dev, unsigned int port) if (!usb_handle_device(dev, &cfg, data, len)) goto fail_mem_free; - switch (usb_get_intf_class(dev->class)) { - case 3: - dprintf("HID found %06X\n", dev->class); - slof_usb_handle(dev); - break; - case 8: - dprintf("MASS STORAGE found %d %06X\n", dev->intf_num, - dev->class); - if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */ - printf("Device not supported %06X\n", dev->class); - goto fail_mem_free; - } - - if (!usb_msc_reset(dev)) { - printf("%s: bulk reset failed\n", __func__); - goto fail_mem_free; - } - SLOF_msleep(100); - slof_usb_handle(dev); - break; - case 9: - dprintf("HUB found\n"); - slof_usb_handle(dev); - break; - default: - printf("USB Interface class -%x- Not supported\n", dev->class); - break; - } - SLOF_dma_free(data, len); return true; fail_mem_free: diff --git a/roms/SLOF/lib/libusb/usb-core.h b/roms/SLOF/lib/libusb/usb-core.h index 7441979e9..a35df3485 100644 --- a/roms/SLOF/lib/libusb/usb-core.h +++ b/roms/SLOF/lib/libusb/usb-core.h @@ -261,6 +261,8 @@ struct usb_hcd_ops { unsigned int usb_type; }; +#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16) + extern void usb_hcd_register(struct usb_hcd_ops *ops); extern struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, char *buf, size_t len); @@ -269,11 +271,12 @@ extern int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf); extern int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data); extern struct usb_dev *usb_devpool_get(void); extern void usb_devpool_put(struct usb_dev *); -extern int setup_new_device(struct usb_dev *dev, unsigned int port); -extern int slof_usb_handle(struct usb_dev *dev); +extern int usb_setup_new_device(struct usb_dev *dev, unsigned int port); +extern void usb_slof_populate_new_device(struct usb_dev *dev); extern int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, void *buf, size_t len); extern int usb_hid_kbd_init(struct usb_dev *dev); extern int usb_hid_kbd_exit(struct usb_dev *dev); +extern int usb_msc_reset(struct usb_dev *dev); extern void usb_msc_resetrecovery(struct usb_dev *dev); #endif diff --git a/roms/SLOF/lib/libusb/usb-ehci.c b/roms/SLOF/lib/libusb/usb-ehci.c index 4cca0da15..60af9e101 100644 --- a/roms/SLOF/lib/libusb/usb-ehci.c +++ b/roms/SLOF/lib/libusb/usb-ehci.c @@ -79,7 +79,9 @@ static int ehci_hub_check_ports(struct ehci_hcd *ehcd) dprintf("usb-ehci: allocated device %p\n", dev); dev->hcidev = ehcd->hcidev; dev->speed = USB_HIGH_SPEED; /* TODO: Check for Low/Full speed device */ - if (!setup_new_device(dev, i)) + if (usb_setup_new_device(dev, i)) + usb_slof_populate_new_device(dev); + else printf("usb-ehci: unable to setup device on port %d\n", i); } } diff --git a/roms/SLOF/lib/libusb/usb-hub.c b/roms/SLOF/lib/libusb/usb-hub.c index 7059cd019..bb8a30915 100644 --- a/roms/SLOF/lib/libusb/usb-hub.c +++ b/roms/SLOF/lib/libusb/usb-hub.c @@ -175,7 +175,9 @@ unsigned int usb_hub_init(void *hubdev) newdev = usb_devpool_get(); dprintf("usb-hub: allocated device %p\n", newdev); newdev->hcidev = dev->hcidev; - if (!setup_new_device(newdev, i)) + if (usb_setup_new_device(newdev, i)) + usb_slof_populate_new_device(newdev); + else printf("usb-hub: unable to setup device on port %d\n", i); } } diff --git a/roms/SLOF/lib/libusb/usb-ohci.c b/roms/SLOF/lib/libusb/usb-ohci.c index 0e8400481..d06c754d1 100644 --- a/roms/SLOF/lib/libusb/usb-ohci.c +++ b/roms/SLOF/lib/libusb/usb-ohci.c @@ -192,7 +192,9 @@ static void ohci_hub_check_ports(struct ohci_hcd *ohcd) dev = usb_devpool_get(); dprintf("usb-ohci: Device reset, setting up %p\n", dev); dev->hcidev = ohcd->hcidev; - if (!setup_new_device(dev, i)) + if (usb_setup_new_device(dev, i)) + usb_slof_populate_new_device(dev); + else printf("usb-ohci: unable to setup device on port %d\n", i); } if (port_status & RH_PS_PESC) { @@ -252,7 +254,7 @@ static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd) return false; ohcd->pool_phys = opipe_phys = SLOF_dma_map_in(opipe, OHCI_PIPE_POOL_SIZE, true); - dprintf("usb-ohci: %s opipe %x, opipe_phys %x size %d count %d\n", + dprintf("usb-ohci: %s opipe %p, opipe_phys %lx size %ld count %d\n", __func__, opipe, opipe_phys, sizeof(*opipe), count); /* Although an array, link them*/ for (i = 0, curr = opipe, prev = NULL; i < count; i++, curr++) { @@ -446,7 +448,7 @@ again: /* Interrupt is there, read from done_head pointer */ td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(hcca->done_head); if (!td_phys) { - dprintf("Again td_phys null %ld\n"); + dprintf("Again td_phys null\n"); goto again; } hcca->done_head = 0; @@ -553,7 +555,7 @@ static int ohci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void * attr = EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps) | EDA_SKIP; ohci_fill_ed(ed, PTR_U32(td_phys), td_next, attr, 0); ed->tailp = 0; /* HACK */ - dprintf("usb-ohci: %s - td_start %x td_end %x req %x\n", __func__, + dprintf("usb-ohci: %s - td_start %p td_end %lx req %lx\n", __func__, td_phys, td_next, req_phys); mb(); ed->attr &= cpu_to_le32(~EDA_SKIP); @@ -642,7 +644,7 @@ static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr, td = tds = (struct ohci_td *) td_ptr; td_phys = (long)td_phys_ptr; - dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %p\n", + dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %lx\n", __func__, pipe, data_phys, datalen, dir, td, td_phys); if (!tds) { @@ -672,7 +674,7 @@ static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr, | EDA_SKIP | pipe->dev->speed | EDA_EP(pipe->epno); td_next = ohci_get_td_phys(td, tds, td_phys); ohci_fill_ed(ed, td_phys, td_next, attr, 0); - dprintf("usb-ohci: %s - tds %p td %p\n", __func__, td_phys, td_next); + dprintf("usb-ohci: %s - tds %lx td %lx\n", __func__, td_phys, td_next); mb(); ed->attr &= cpu_to_le32(~EDA_SKIP); @@ -778,7 +780,7 @@ static int ohci_get_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd, td->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC); td->next_td = cpu_to_le32(td_next); td->be = cpu_to_le32(PTR_U32(ptr) + mps - 1); - dprintf("td %x td++ %x ptr %x be %x\n", + dprintf("td %p td++ %x ptr %p be %x\n", td, le32_to_cpu(td->next_td), ptr, (PTR_U32(ptr) + mps - 1)); } diff --git a/roms/SLOF/lib/libusb/usb-slof.c b/roms/SLOF/lib/libusb/usb-slof.c index de841f0fb..ff070559a 100644 --- a/roms/SLOF/lib/libusb/usb-slof.c +++ b/roms/SLOF/lib/libusb/usb-slof.c @@ -26,7 +26,7 @@ #define dprintf(_x ...) #endif -int slof_usb_handle(struct usb_dev *dev) +static int slof_usb_handle(struct usb_dev *dev) { struct slof_usb_dev sdev; sdev.port = dev->port; @@ -59,3 +59,35 @@ int slof_usb_handle(struct usb_dev *dev) } return true; } + +void usb_slof_populate_new_device(struct usb_dev *dev) +{ + switch (usb_get_intf_class(dev->class)) { + case 3: + dprintf("HID found %06X\n", dev->class); + slof_usb_handle(dev); + break; + case 8: + dprintf("MASS STORAGE found %d %06X\n", dev->intf_num, + dev->class); + if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */ + printf("Device not supported %06X\n", dev->class); + break; + } + + if (!usb_msc_reset(dev)) { + printf("%s: bulk reset failed\n", __func__); + break; + } + SLOF_msleep(100); + slof_usb_handle(dev); + break; + case 9: + dprintf("HUB found\n"); + slof_usb_handle(dev); + break; + default: + printf("USB Interface class -%x- Not supported\n", dev->class); + break; + } +} diff --git a/roms/SLOF/lib/libusb/usb-xhci.c b/roms/SLOF/lib/libusb/usb-xhci.c index 7683c51d6..858cd12f9 100644 --- a/roms/SLOF/lib/libusb/usb-xhci.c +++ b/roms/SLOF/lib/libusb/usb-xhci.c @@ -608,8 +608,10 @@ static bool xhci_alloc_dev(struct xhci_hcd *xhcd, uint32_t slot_id, uint32_t por dev->port = newport; dev->priv = xdev; xdev->dev = dev; - if (setup_new_device(dev, newport)) + if (usb_setup_new_device(dev, newport)) { + usb_slof_populate_new_device(dev); return true; + } xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE); fail_control_seg: diff --git a/roms/SLOF/lib/libvirtio/p9.c b/roms/SLOF/lib/libvirtio/p9.c index a55662994..0e5953031 100644 --- a/roms/SLOF/lib/libvirtio/p9.c +++ b/roms/SLOF/lib/libvirtio/p9.c @@ -143,7 +143,7 @@ int p9_transaction(p9_connection_t *connection) { int rc; int tx_size = GET_SIZE; - int rx_size = connection->message_size; + uint32_t rx_size = connection->message_size; if (transact == NULL) { return P9_NO_TRANSPORT; diff --git a/roms/SLOF/lib/libvirtio/p9.h b/roms/SLOF/lib/libvirtio/p9.h index 7df9ef441..3a35e80ed 100644 --- a/roms/SLOF/lib/libvirtio/p9.h +++ b/roms/SLOF/lib/libvirtio/p9.h @@ -33,7 +33,7 @@ #define P9_PARTIAL_WALK 1 typedef int (*p9_transact_t)(void *opaque, uint8_t *tx, int tx_size, - uint8_t *rx, int *rx_size); + uint8_t *rx, uint32_t *rx_size); typedef struct { uint32_t message_size; diff --git a/roms/SLOF/lib/libvirtio/virtio-9p.c b/roms/SLOF/lib/libvirtio/virtio-9p.c index 5a5fd01da..fc5db9154 100644 --- a/roms/SLOF/lib/libvirtio/virtio-9p.c +++ b/roms/SLOF/lib/libvirtio/virtio-9p.c @@ -19,6 +19,7 @@ #include "virtio-9p.h" #include "p9.h" +static struct vqs vq; /** * Notes for 9P Server config: @@ -86,7 +87,7 @@ static void dprint_buffer(const char *name, uint8_t *buffer, int length) * @return 0 = success, -ve = error. */ static int virtio_9p_transact(void *opaque, uint8_t *tx, int tx_size, uint8_t *rx, - int *rx_size) + uint32_t *rx_size) { struct virtio_device *dev = opaque; struct vring_desc *desc; @@ -165,6 +166,7 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf, int buf_size) { struct vring_avail *vq_avail; + int status = VIRTIO_STAT_ACKNOWLEDGE; /* Check for double open */ if (__buf_size) @@ -174,28 +176,31 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf, dprintf("%s : device at %p\n", __func__, dev->base); dprintf("%s : type is %04x\n", __func__, dev->type); - /* Reset device */ - // XXX That will clear the virtq base. We need to move - // initializing it to here anyway - // - // virtio_reset_device(dev); + /* Keep it disabled until the driver is 1.0 capable */ + dev->is_modern = false; + + virtio_reset_device(dev); /* Acknowledge device. */ - virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE); + virtio_set_status(dev, status); /* Tell HV that we know how to drive the device. */ - virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER); + status |= VIRTIO_STAT_DRIVER; + virtio_set_status(dev, status); /* Device specific setup - we do not support special features */ virtio_set_guest_features(dev, 0); + if (virtio_queue_init_vq(dev, &vq, 0)) + goto dev_error; + vq_avail = virtio_get_vring_avail(dev, 0); vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT; vq_avail->idx = 0; /* Tell HV that setup succeeded */ - virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER - |VIRTIO_STAT_DRIVER_OK); + status |= VIRTIO_STAT_DRIVER_OK; + virtio_set_status(dev, status); /* Setup 9P library. */ p9_reg_transport(virtio_9p_transact, dev,(uint8_t *)tx_buf, @@ -203,6 +208,12 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf, dprintf("%s : complete\n", __func__); return 0; + +dev_error: + printf("%s: failed\n", __func__); + status |= VIRTIO_STAT_FAILED; + virtio_set_status(dev, status); + return -1; } /** @@ -228,7 +239,7 @@ void virtio_9p_shutdown(struct virtio_device *dev) * @param buffer[out] Where to read the file to. * @return +ve = amount of data read, -ve = error. */ -int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer) +long virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer) { int rc; uint16_t tag_len; @@ -332,5 +343,5 @@ cleanup_connection: dprintf("%s : complete, read %llu bytes\n", __func__, offset); - return rc == 0 ? offset : rc; + return rc == 0 ? (long)offset : rc; } diff --git a/roms/SLOF/lib/libvirtio/virtio-9p.h b/roms/SLOF/lib/libvirtio/virtio-9p.h index 4bf47d078..db2cf6f11 100644 --- a/roms/SLOF/lib/libvirtio/virtio-9p.h +++ b/roms/SLOF/lib/libvirtio/virtio-9p.h @@ -26,7 +26,7 @@ typedef struct { int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf, int buf_size); void virtio_9p_shutdown(struct virtio_device *dev); -int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer); +long virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer); #endif /* VIRTIO_9P_H_ */ diff --git a/roms/SLOF/lib/libvirtio/virtio-blk.c b/roms/SLOF/lib/libvirtio/virtio-blk.c index 826f2ea0e..07ec1048f 100644 --- a/roms/SLOF/lib/libvirtio/virtio-blk.c +++ b/roms/SLOF/lib/libvirtio/virtio-blk.c @@ -13,10 +13,15 @@ #include <stdio.h> #include <cpu.h> #include <helpers.h> +#include <byteorder.h> #include "virtio.h" #include "virtio-blk.h" +#include "virtio-internal.h" #define DEFAULT_SECTOR_SIZE 512 +#define DRIVER_FEATURE_SUPPORT (VIRTIO_BLK_F_BLK_SIZE | VIRTIO_F_VERSION_1) + +static struct vqs vq; /** * Initialize virtio-block device. @@ -27,39 +32,54 @@ virtioblk_init(struct virtio_device *dev) { struct vring_avail *vq_avail; int blk_size = DEFAULT_SECTOR_SIZE; - int features; + uint64_t features; + int status = VIRTIO_STAT_ACKNOWLEDGE; /* Reset device */ - // XXX That will clear the virtq base. We need to move - // initializing it to here anyway - // - // virtio_reset_device(dev); + virtio_reset_device(dev); /* Acknowledge device. */ - virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE); + virtio_set_status(dev, status); /* Tell HV that we know how to drive the device. */ - virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER); + status |= VIRTIO_STAT_DRIVER; + virtio_set_status(dev, status); + + if (dev->is_modern) { + /* Negotiate features and sets FEATURES_OK if successful */ + if (virtio_negotiate_guest_features(dev, DRIVER_FEATURE_SUPPORT)) + goto dev_error; + + virtio_get_status(dev, &status); + } else { + /* Device specific setup - we support F_BLK_SIZE */ + virtio_set_guest_features(dev, VIRTIO_BLK_F_BLK_SIZE); + } - /* Device specific setup - we support F_BLK_SIZE */ - virtio_set_guest_features(dev, VIRTIO_BLK_F_BLK_SIZE); + if (virtio_queue_init_vq(dev, &vq, 0)) + goto dev_error; vq_avail = virtio_get_vring_avail(dev, 0); - vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT; + vq_avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT); vq_avail->idx = 0; /* Tell HV that setup succeeded */ - virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER - |VIRTIO_STAT_DRIVER_OK); + status |= VIRTIO_STAT_DRIVER_OK; + virtio_set_status(dev, status); - virtio_get_host_features(dev, &features); + features = virtio_get_host_features(dev); if (features & VIRTIO_BLK_F_BLK_SIZE) { blk_size = virtio_get_config(dev, - offset_of(struct virtio_blk_cfg, blk_size), - sizeof(blk_size)); + offset_of(struct virtio_blk_cfg, blk_size), + sizeof(blk_size)); } return blk_size; +dev_error: + printf("%s: failed\n", __func__); + status |= VIRTIO_STAT_FAILED; + virtio_set_status(dev, status); + return 0; } @@ -77,6 +97,19 @@ virtioblk_shutdown(struct virtio_device *dev) virtio_reset_device(dev); } +static void fill_blk_hdr(struct virtio_blk_req *blkhdr, bool is_modern, + uint32_t type, uint32_t ioprio, uint32_t sector) +{ + if (is_modern) { + blkhdr->type = cpu_to_le32(type); + blkhdr->ioprio = cpu_to_le32(ioprio); + blkhdr->sector = cpu_to_le64(sector); + } else { + blkhdr->type = type; + blkhdr->ioprio = ioprio; + blkhdr->sector = sector; + } +} /** * Read blocks @@ -87,7 +120,7 @@ virtioblk_shutdown(struct virtio_device *dev) * @return number of blocks that have been read successfully */ int -virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt) +virtioblk_read(struct virtio_device *dev, char *buf, uint64_t blocknum, long cnt) { struct vring_desc *desc; int id; @@ -100,7 +133,7 @@ virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt) struct vring_used *vq_used; /* "Used" vring */ volatile uint8_t status = -1; volatile uint16_t *current_used_idx; - uint16_t last_used_idx; + uint16_t last_used_idx, avail_idx; int blk_size = DEFAULT_SECTOR_SIZE; //printf("virtioblk_read: dev=%p buf=%p blocknum=%li count=%li\n", @@ -128,41 +161,38 @@ virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt) vq_avail = virtio_get_vring_avail(dev, 0); vq_used = virtio_get_vring_used(dev, 0); + avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx); + last_used_idx = vq_used->idx; current_used_idx = &vq_used->idx; /* Set up header */ - blkhdr.type = VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER; - blkhdr.ioprio = 1; - blkhdr.sector = blocknum * blk_size / DEFAULT_SECTOR_SIZE; + fill_blk_hdr(&blkhdr, dev->is_modern, VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER, + 1, blocknum * blk_size / DEFAULT_SECTOR_SIZE); /* Determine descriptor index */ - id = (vq_avail->idx * 3) % vq_size; + id = (avail_idx * 3) % vq_size; /* Set up virtqueue descriptor for header */ desc = &vq_desc[id]; - desc->addr = (uint64_t)&blkhdr; - desc->len = sizeof(struct virtio_blk_req); - desc->flags = VRING_DESC_F_NEXT; - desc->next = (id + 1) % vq_size; + virtio_fill_desc(desc, dev->is_modern, (uint64_t)&blkhdr, + sizeof(struct virtio_blk_req), + VRING_DESC_F_NEXT, (id + 1) % vq_size); /* Set up virtqueue descriptor for data */ desc = &vq_desc[(id + 1) % vq_size]; - desc->addr = (uint64_t)buf; - desc->len = cnt * blk_size; - desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; - desc->next = (id + 2) % vq_size; + virtio_fill_desc(desc, dev->is_modern, (uint64_t)buf, cnt * blk_size, + VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, + (id + 2) % vq_size); /* Set up virtqueue descriptor for status */ desc = &vq_desc[(id + 2) % vq_size]; - desc->addr = (uint64_t)&status; - desc->len = 1; - desc->flags = VRING_DESC_F_WRITE; - desc->next = 0; + virtio_fill_desc(desc, dev->is_modern, (uint64_t)&status, 1, + VRING_DESC_F_WRITE, 0); - vq_avail->ring[vq_avail->idx % vq_size] = id; + vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16 (dev, id); mb(); - vq_avail->idx += 1; + vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1); /* Tell HV that the queue is ready */ virtio_queue_notify(dev, 0); diff --git a/roms/SLOF/lib/libvirtio/virtio-blk.h b/roms/SLOF/lib/libvirtio/virtio-blk.h index ac8bf2896..2e7b5926b 100644 --- a/roms/SLOF/lib/libvirtio/virtio-blk.h +++ b/roms/SLOF/lib/libvirtio/virtio-blk.h @@ -55,6 +55,6 @@ struct virtio_blk_req { extern int virtioblk_init(struct virtio_device *dev); extern void virtioblk_shutdown(struct virtio_device *dev); -extern int virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt); +extern int virtioblk_read(struct virtio_device *dev, char *buf, uint64_t blocknum, long cnt); #endif /* _VIRTIO_BLK_H */ diff --git a/roms/SLOF/lib/libvirtio/virtio-internal.h b/roms/SLOF/lib/libvirtio/virtio-internal.h new file mode 100644 index 000000000..08662eab7 --- /dev/null +++ b/roms/SLOF/lib/libvirtio/virtio-internal.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * Copyright (c) 2016 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _LIBVIRTIO_INTERNAL_H +#define _LIBVIRTIO_INTERNAL_H + +#include <byteorder.h> + +static inline uint16_t virtio_cpu_to_modern16(struct virtio_device *dev, uint16_t val) +{ + return dev->is_modern ? cpu_to_le16(val) : val; +} + +static inline uint32_t virtio_cpu_to_modern32(struct virtio_device *dev, uint32_t val) +{ + return dev->is_modern ? cpu_to_le32(val) : val; +} + +static inline uint64_t virtio_cpu_to_modern64(struct virtio_device *dev, uint64_t val) +{ + return dev->is_modern ? cpu_to_le64(val) : val; +} + +static inline uint16_t virtio_modern16_to_cpu(struct virtio_device *dev, uint16_t val) +{ + return dev->is_modern ? le16_to_cpu(val) : val; +} + +static inline uint32_t virtio_modern32_to_cpu(struct virtio_device *dev, uint32_t val) +{ + return dev->is_modern ? le32_to_cpu(val) : val; +} + +static inline uint64_t virtio_modern64_to_cpu(struct virtio_device *dev, uint64_t val) +{ + return dev->is_modern ? le64_to_cpu(val) : val; +} + +#endif /* _LIBVIRTIO_INTERNAL_H */ diff --git a/roms/SLOF/lib/libvirtio/virtio-net.c b/roms/SLOF/lib/libvirtio/virtio-net.c index 99c19d952..fc620a201 100644 --- a/roms/SLOF/lib/libvirtio/virtio-net.c +++ b/roms/SLOF/lib/libvirtio/virtio-net.c @@ -26,6 +26,7 @@ #include <byteorder.h> #include "virtio.h" #include "virtio-net.h" +#include "virtio-internal.h" #undef DEBUG //#define DEBUG @@ -37,22 +38,13 @@ #define sync() asm volatile (" sync \n" ::: "memory") -/* PCI virtio header offsets */ -#define VIRTIOHDR_DEVICE_FEATURES 0 -#define VIRTIOHDR_GUEST_FEATURES 4 -#define VIRTIOHDR_QUEUE_ADDRESS 8 -#define VIRTIOHDR_QUEUE_SIZE 12 -#define VIRTIOHDR_QUEUE_SELECT 14 -#define VIRTIOHDR_QUEUE_NOTIFY 16 -#define VIRTIOHDR_DEVICE_STATUS 18 -#define VIRTIOHDR_ISR_STATUS 19 -#define VIRTIOHDR_DEVICE_CONFIG 20 -#define VIRTIOHDR_MAC_ADDRESS 20 +#define DRIVER_FEATURE_SUPPORT (VIRTIO_NET_F_MAC | VIRTIO_F_VERSION_1) struct virtio_device virtiodev; -struct vqs vq[2]; /* Information about virtqueues */ +static struct vqs vq_rx; /* Information about receive virtqueues */ +static struct vqs vq_tx; /* Information about transmit virtqueues */ -/* See Virtio Spec, appendix C, "Device Operation" */ +/* See Virtio Spec, appendix C, "Device Operation" */ struct virtio_net_hdr { uint8_t flags; uint8_t gso_type; @@ -63,6 +55,18 @@ struct virtio_net_hdr { // uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */ }; +static unsigned int net_hdr_size; + +struct virtio_net_hdr_v1 { + uint8_t flags; + uint8_t gso_type; + le16 hdr_len; + le16 gso_size; + le16 csum_start; + le16 csum_offset; + le16 num_buffers; +}; + static uint16_t last_rx_idx; /* Last index in RX "used" ring */ /** @@ -72,15 +76,13 @@ static uint16_t last_rx_idx; /* Last index in RX "used" ring */ */ static int virtionet_init_pci(struct virtio_device *dev) { - int i; - dprintf("virtionet: doing virtionet_init_pci!\n"); if (!dev) return -1; - virtiodev.base = dev->base; - virtiodev.type = dev->type; + /* make a copy of the device structure */ + memcpy(&virtiodev, dev, sizeof(struct virtio_device)); /* Reset device */ virtio_reset_device(&virtiodev); @@ -90,29 +92,11 @@ static int virtionet_init_pci(struct virtio_device *dev) * second the transmit queue, and the forth is the control queue for * networking options. * We are only interested in the receive and transmit queue here. */ - - for (i=VQ_RX; i<=VQ_TX; i++) { - /* Select ring (0=RX, 1=TX): */ - vq[i].id = i-VQ_RX; - ci_write_16(virtiodev.base+VIRTIOHDR_QUEUE_SELECT, - cpu_to_le16(vq[i].id)); - - vq[i].size = le16_to_cpu(ci_read_16(virtiodev.base+VIRTIOHDR_QUEUE_SIZE)); - vq[i].desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq[i].size), 4096); - if (!vq[i].desc) { - printf("memory allocation failed!\n"); - return -1; - } - memset(vq[i].desc, 0, virtio_vring_size(vq[i].size)); - ci_write_32(virtiodev.base+VIRTIOHDR_QUEUE_ADDRESS, - cpu_to_le32((long)vq[i].desc / 4096)); - vq[i].avail = (void*)vq[i].desc - + vq[i].size * sizeof(struct vring_desc); - vq[i].used = (void*)VQ_ALIGN((long)vq[i].avail - + vq[i].size * sizeof(struct vring_avail)); - - dprintf("%i: vq.id = %llx\nvq.size =%x\n vq.avail =%p\nvq.used=%p\n", - i, vq[i].id, vq[i].size, vq[i].avail, vq[i].used); + if (virtio_queue_init_vq(dev, &vq_rx, VQ_RX) || + virtio_queue_init_vq(dev, &vq_tx, VQ_TX)) { + virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER + |VIRTIO_STAT_FAILED); + return -1; } /* Acknowledge device. */ @@ -129,6 +113,7 @@ static int virtionet_init_pci(struct virtio_device *dev) static int virtionet_init(net_driver_t *driver) { int i; + int status = VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER; dprintf("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n", driver->mac_addr[0], driver->mac_addr[1], @@ -139,60 +124,69 @@ static int virtionet_init(net_driver_t *driver) return 0; /* Tell HV that we know how to drive the device. */ - virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER); - - /* Device specific setup - we do not support special features right now */ - virtio_set_guest_features(&virtiodev, 0); + virtio_set_status(&virtiodev, status); + + /* Device specific setup */ + if (virtiodev.is_modern) { + if (virtio_negotiate_guest_features(&virtiodev, DRIVER_FEATURE_SUPPORT)) + goto dev_error; + net_hdr_size = sizeof(struct virtio_net_hdr_v1); + virtio_get_status(&virtiodev, &status); + } else { + net_hdr_size = sizeof(struct virtio_net_hdr); + virtio_set_guest_features(&virtiodev, 0); + } /* Allocate memory for one transmit an multiple receive buffers */ - vq[VQ_RX].buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr)) + vq_rx.buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+net_hdr_size) * RX_QUEUE_SIZE); - if (!vq[VQ_RX].buf_mem) { + if (!vq_rx.buf_mem) { printf("virtionet: Failed to allocate buffers!\n"); - virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED); - return -1; + goto dev_error; } /* Prepare receive buffer queue */ for (i = 0; i < RX_QUEUE_SIZE; i++) { - struct vring_desc *desc; + uint64_t addr = (uint64_t)vq_rx.buf_mem + + i * (BUFFER_ENTRY_SIZE+net_hdr_size); + uint32_t id = i*2; /* Descriptor for net_hdr: */ - desc = &vq[VQ_RX].desc[i*2]; - desc->addr = (uint64_t)vq[VQ_RX].buf_mem - + i * (BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr)); - desc->len = sizeof(struct virtio_net_hdr); - desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; - desc->next = i*2+1; + virtio_fill_desc(&vq_rx.desc[id], virtiodev.is_modern, addr, net_hdr_size, + VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, id + 1); /* Descriptor for data: */ - desc = &vq[VQ_RX].desc[i*2+1]; - desc->addr = vq[VQ_RX].desc[i*2].addr + sizeof(struct virtio_net_hdr); - desc->len = BUFFER_ENTRY_SIZE; - desc->flags = VRING_DESC_F_WRITE; - desc->next = 0; + virtio_fill_desc(&vq_rx.desc[id+1], virtiodev.is_modern, addr + net_hdr_size, + BUFFER_ENTRY_SIZE, VRING_DESC_F_WRITE, 0); - vq[VQ_RX].avail->ring[i] = i*2; + vq_rx.avail->ring[i] = virtio_cpu_to_modern16(&virtiodev, id); } sync(); - vq[VQ_RX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT; - vq[VQ_RX].avail->idx = RX_QUEUE_SIZE; - last_rx_idx = vq[VQ_RX].used->idx; + vq_rx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT); + vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, RX_QUEUE_SIZE); + + last_rx_idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx); - vq[VQ_TX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT; - vq[VQ_TX].avail->idx = 0; + vq_tx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT); + vq_tx.avail->idx = 0; /* Tell HV that setup succeeded */ - virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE - |VIRTIO_STAT_DRIVER - |VIRTIO_STAT_DRIVER_OK); + status |= VIRTIO_STAT_DRIVER_OK; + virtio_set_status(&virtiodev, status); /* Tell HV that RX queues are ready */ virtio_queue_notify(&virtiodev, VQ_RX); driver->running = 1; - + for(i = 0; i < (int)sizeof(driver->mac_addr); i++) { + driver->mac_addr[i] = virtio_get_config(&virtiodev, i, 1); + } return 0; + +dev_error: + status |= VIRTIO_STAT_FAILED; + virtio_set_status(&virtiodev, status); + return -1; } @@ -225,9 +219,10 @@ static int virtionet_term(net_driver_t *driver) */ static int virtionet_xmit(char *buf, int len) { - struct vring_desc *desc; - int id; - static struct virtio_net_hdr nethdr; + int id, idx; + static struct virtio_net_hdr_v1 nethdr_v1; + static struct virtio_net_hdr nethdr_legacy; + void *nethdr = &nethdr_legacy; if (len > BUFFER_ENTRY_SIZE) { printf("virtionet: Packet too big!\n"); @@ -236,28 +231,25 @@ static int virtionet_xmit(char *buf, int len) dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len); - memset(&nethdr, 0, sizeof(nethdr)); + if (virtiodev.is_modern) + nethdr = &nethdr_v1; + + memset(nethdr, 0, net_hdr_size); /* Determine descriptor index */ - id = (vq[VQ_TX].avail->idx * 2) % vq[VQ_TX].size; + idx = virtio_modern16_to_cpu(&virtiodev, vq_tx.avail->idx); + id = (idx * 2) % vq_tx.size; /* Set up virtqueue descriptor for header */ - desc = &vq[VQ_TX].desc[id]; - desc->addr = (uint64_t)&nethdr; - desc->len = sizeof(struct virtio_net_hdr); - desc->flags = VRING_DESC_F_NEXT; - desc->next = id + 1; + virtio_fill_desc(&vq_tx.desc[id], virtiodev.is_modern, (uint64_t)nethdr, + net_hdr_size, VRING_DESC_F_NEXT, id + 1); /* Set up virtqueue descriptor for data */ - desc = &vq[VQ_TX].desc[id+1]; - desc->addr = (uint64_t)buf; - desc->len = len; - desc->flags = 0; - desc->next = 0; + virtio_fill_desc(&vq_tx.desc[id+1], virtiodev.is_modern, (uint64_t)buf, len, 0, 0); - vq[VQ_TX].avail->ring[vq[VQ_TX].avail->idx % vq[VQ_TX].size] = id; + vq_tx.avail->ring[idx % vq_tx.size] = virtio_cpu_to_modern16(&virtiodev, id); sync(); - vq[VQ_TX].avail->idx += 1; + vq_tx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1); sync(); /* Tell HV that TX queue is ready */ @@ -272,23 +264,24 @@ static int virtionet_xmit(char *buf, int len) */ static int virtionet_receive(char *buf, int maxlen) { - int len = 0; - int id; + uint32_t len = 0; + uint32_t id, idx; - if (last_rx_idx == vq[VQ_RX].used->idx) { + idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx); + + if (last_rx_idx == idx) { /* Nothing received yet */ return 0; } - id = (vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].id + 1) - % vq[VQ_RX].size; - len = vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].len - - sizeof(struct virtio_net_hdr); - - dprintf("virtionet_receive() last_rx_idx=%i, vq[VQ_RX].used->idx=%i," - " id=%i len=%i\n", last_rx_idx, vq[VQ_RX].used->idx, id, len); + id = (virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].id) + 1) + % vq_rx.size; + len = virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].len) + - net_hdr_size; + dprintf("virtionet_receive() last_rx_idx=%i, vq_rx.used->idx=%i," + " id=%i len=%i\n", last_rx_idx, vq_rx.used->idx, id, len); - if (len > maxlen) { + if (len > (uint32_t)maxlen) { printf("virtio-net: Receive buffer not big enough!\n"); len = maxlen; } @@ -298,7 +291,7 @@ static int virtionet_receive(char *buf, int maxlen) printf("\n"); int i; for (i=0; i<64; i++) { - printf(" %02x", *(uint8_t*)(vq[VQ_RX].desc[id].addr+i)); + printf(" %02x", *(uint8_t*)(vq_rx.desc[id].addr+i)); if ((i%16)==15) printf("\n"); } @@ -306,14 +299,14 @@ static int virtionet_receive(char *buf, int maxlen) #endif /* Copy data to destination buffer */ - memcpy(buf, (void*)vq[VQ_RX].desc[id].addr, len); + memcpy(buf, (void *)virtio_modern64_to_cpu(&virtiodev, vq_rx.desc[id].addr), len); /* Move indices to next entries */ last_rx_idx = last_rx_idx + 1; - vq[VQ_RX].avail->ring[vq[VQ_RX].avail->idx % vq[VQ_RX].size] = id - 1; + vq_rx.avail->ring[idx % vq_rx.size] = virtio_cpu_to_modern16(&virtiodev, id - 1); sync(); - vq[VQ_RX].avail->idx += 1; + vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1); /* Tell HV that RX queue entry is ready */ virtio_queue_notify(&virtiodev, VQ_RX); @@ -321,7 +314,7 @@ static int virtionet_receive(char *buf, int maxlen) return len; } -net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev) +net_driver_t *virtionet_open(struct virtio_device *dev) { net_driver_t *driver; @@ -331,7 +324,6 @@ net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev) return NULL; } - memcpy(driver->mac_addr, mac_addr, 6); driver->running = 0; if (virtionet_init_pci(dev)) diff --git a/roms/SLOF/lib/libvirtio/virtio-net.h b/roms/SLOF/lib/libvirtio/virtio-net.h index bc7a189f7..c2d8ee336 100644 --- a/roms/SLOF/lib/libvirtio/virtio-net.h +++ b/roms/SLOF/lib/libvirtio/virtio-net.h @@ -23,19 +23,10 @@ enum { VQ_TX = 1, /* Transmit Queue */ }; -struct vqs { - uint64_t id; /* Queue ID */ - uint32_t size; - void *buf_mem; - struct vring_desc *desc; - struct vring_avail *avail; - struct vring_used *used; -}; - -/* Device is identified by RX queue ID: */ -#define DEVICE_ID vq[0].id +/* VIRTIO_NET Feature bits */ +#define VIRTIO_NET_F_MAC (1 << 5) -extern net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev); +extern net_driver_t *virtionet_open(struct virtio_device *dev); extern void virtionet_close(net_driver_t *driver); extern int virtionet_read(char *buf, int len); extern int virtionet_write(char *buf, int len); diff --git a/roms/SLOF/lib/libvirtio/virtio-scsi.c b/roms/SLOF/lib/libvirtio/virtio-scsi.c index 48289289a..04181b06c 100644 --- a/roms/SLOF/lib/libvirtio/virtio-scsi.c +++ b/roms/SLOF/lib/libvirtio/virtio-scsi.c @@ -15,6 +15,7 @@ #include <cpu.h> #include <helpers.h> #include "virtio.h" +#include "virtio-internal.h" #include "virtio-scsi.h" int virtioscsi_send(struct virtio_device *dev, @@ -22,58 +23,54 @@ int virtioscsi_send(struct virtio_device *dev, struct virtio_scsi_resp_cmd *resp, int is_read, void *buf, uint64_t buf_len) { - struct vring_desc *desc; - struct vring_desc *vq_desc; /* Descriptor vring */ - struct vring_avail *vq_avail; /* "Available" vring */ - struct vring_used *vq_used; /* "Used" vring */ - - volatile uint16_t *current_used_idx; - uint16_t last_used_idx; - int id; - uint32_t vq_size, time; - - int vq = VIRTIO_SCSI_REQUEST_VQ; - - vq_size = virtio_get_qsize(dev, vq); - vq_desc = virtio_get_vring_desc(dev, vq); - vq_avail = virtio_get_vring_avail(dev, vq); - vq_used = virtio_get_vring_used(dev, vq); - - last_used_idx = vq_used->idx; - current_used_idx = &vq_used->idx; - - /* Determine descriptor index */ - id = (vq_avail->idx * 3) % vq_size; - - desc = &vq_desc[id]; - desc->addr = (uint64_t)req; - desc->len = sizeof(*req); - desc->flags = VRING_DESC_F_NEXT; - desc->next = (id + 1) % vq_size; - - /* Set up virtqueue descriptor for data */ - desc = &vq_desc[(id + 1) % vq_size]; - desc->addr = (uint64_t)resp; - desc->len = sizeof(*resp); - desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; - desc->next = (id + 2) % vq_size; - - if (buf && buf_len) { - /* Set up virtqueue descriptor for status */ - desc = &vq_desc[(id + 2) % vq_size]; - desc->addr = (uint64_t)buf; - desc->len = buf_len; - desc->flags = is_read ? VRING_DESC_F_WRITE : 0; - desc->next = 0; - } else - desc->flags &= ~VRING_DESC_F_NEXT; - - vq_avail->ring[vq_avail->idx % vq_size] = id; - mb(); - vq_avail->idx += 1; - - /* Tell HV that the vq is ready */ - virtio_queue_notify(dev, vq); + struct vring_desc *vq_desc; /* Descriptor vring */ + struct vring_avail *vq_avail; /* "Available" vring */ + struct vring_used *vq_used; /* "Used" vring */ + + volatile uint16_t *current_used_idx; + uint16_t last_used_idx, avail_idx; + int id; + uint32_t vq_size, time; + + int vq = VIRTIO_SCSI_REQUEST_VQ; + + vq_size = virtio_get_qsize(dev, vq); + vq_desc = virtio_get_vring_desc(dev, vq); + vq_avail = virtio_get_vring_avail(dev, vq); + vq_used = virtio_get_vring_used(dev, vq); + + avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx); + + last_used_idx = vq_used->idx; + current_used_idx = &vq_used->idx; + + /* Determine descriptor index */ + id = (avail_idx * 3) % vq_size; + virtio_fill_desc(&vq_desc[id], dev->is_modern, (uint64_t)req, sizeof(*req), VRING_DESC_F_NEXT, + (id + 1) % vq_size); + + /* Set up virtqueue descriptor for data */ + if (buf && buf_len) { + virtio_fill_desc(&vq_desc[(id + 1) % vq_size], dev->is_modern, + (uint64_t)resp, sizeof(*resp), + VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, + (id + 2) % vq_size); + /* Set up virtqueue descriptor for status */ + virtio_fill_desc(&vq_desc[(id + 2) % vq_size], dev->is_modern, + (uint64_t)buf, buf_len, + (is_read ? VRING_DESC_F_WRITE : 0), 0); + } else { + virtio_fill_desc(&vq_desc[(id + 1) % vq_size], dev->is_modern, + (uint64_t)resp, sizeof(*resp), + VRING_DESC_F_WRITE, 0); + } + + vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16(dev, id); + mb(); + vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1); + + /* Tell HV that the vq is ready */ + virtio_queue_notify(dev, vq); /* Wait for host to consume the descriptor */ time = SLOF_GetTimer() + VIRTIO_TIMEOUT; @@ -84,7 +81,7 @@ int virtioscsi_send(struct virtio_device *dev, break; } - return 0; + return 0; } /** @@ -93,42 +90,55 @@ int virtioscsi_send(struct virtio_device *dev, */ int virtioscsi_init(struct virtio_device *dev) { - struct vring_avail *vq_avail; - unsigned int idx = 0; - int qsize = 0; - - /* Reset device */ - // XXX That will clear the virtq base. We need to move - // initializing it to here anyway - // - // virtio_reset_device(dev); - - /* Acknowledge device. */ - virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE); + struct vring_avail *vq_avail; + unsigned int idx = 0; + int qsize = 0; + int status = VIRTIO_STAT_ACKNOWLEDGE; - /* Tell HV that we know how to drive the device. */ - virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER); - - /* Device specific setup - we do not support special features right now */ - virtio_set_guest_features(dev, 0); + /* Reset device */ + // XXX That will clear the virtq base. We need to move + // initializing it to here anyway + // + // virtio_reset_device(dev); + + /* Acknowledge device. */ + virtio_set_status(dev, status); + + /* Tell HV that we know how to drive the device. */ + status |= VIRTIO_STAT_DRIVER; + virtio_set_status(dev, status); + + /* Device specific setup - we do not support special features right now */ + if (dev->is_modern) { + if (virtio_negotiate_guest_features(dev, VIRTIO_F_VERSION_1)) + goto dev_error; + virtio_get_status(dev, &status); + } else { + virtio_set_guest_features(dev, 0); + } - while(1) { - qsize = virtio_get_qsize(dev, idx); - if (!qsize) - break; - virtio_vring_size(qsize); + while(1) { + qsize = virtio_get_qsize(dev, idx); + if (!qsize) + break; + virtio_vring_size(qsize); - vq_avail = virtio_get_vring_avail(dev, 0); - vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT; - vq_avail->idx = 0; - idx++; - } + vq_avail = virtio_get_vring_avail(dev, idx); + vq_avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT); + vq_avail->idx = 0; + idx++; + } /* Tell HV that setup succeeded */ - virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER - |VIRTIO_STAT_DRIVER_OK); + status |= VIRTIO_STAT_DRIVER_OK; + virtio_set_status(dev, status); return 0; +dev_error: + printf("%s: failed\n", __func__); + status |= VIRTIO_STAT_FAILED; + virtio_set_status(dev, status); + return -1; } /** diff --git a/roms/SLOF/lib/libvirtio/virtio.c b/roms/SLOF/lib/libvirtio/virtio.c index f9c00a67a..f189941c7 100644 --- a/roms/SLOF/lib/libvirtio/virtio.c +++ b/roms/SLOF/lib/libvirtio/virtio.c @@ -10,10 +10,16 @@ * IBM Corporation - initial implementation *****************************************************************************/ +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> #include <cpu.h> #include <cache.h> #include <byteorder.h> #include "virtio.h" +#include "helpers.h" /* PCI virtio header offsets */ #define VIRTIOHDR_DEVICE_FEATURES 0 @@ -26,6 +32,166 @@ #define VIRTIOHDR_ISR_STATUS 19 #define VIRTIOHDR_DEVICE_CONFIG 20 +/* PCI defines */ +#define PCI_BASE_ADDR_SPACE_IO 0x01 +#define PCI_BASE_ADDR_SPACE_64BIT 0x04 +#define PCI_BASE_ADDR_MEM_MASK (~0x0fUL) +#define PCI_BASE_ADDR_IO_MASK (~0x03UL) + +#define PCI_BASE_ADDR_REG_0 0x10 +#define PCI_CONFIG_CAP_REG 0x34 + +#define PCI_CAP_ID_VNDR 0x9 + +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR access */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +#define VIRTIO_PCI_CAP_VNDR 0 /* Generic PCI field: PCI_CAP_ID_VNDR */ +#define VIRTIO_PCI_CAP_NEXT 1 /* Generic PCI field: next ptr. */ +#define VIRTIO_PCI_CAP_LEN 2 /* Generic PCI field: capability length */ +#define VIRTIO_PCI_CAP_CFG_TYPE 3 /* Identifies the structure. */ +#define VIRTIO_PCI_CAP_BAR 4 /* Where to find it. */ +#define VIRTIO_PCI_CAP_OFFSET 8 /* Offset within bar. */ +#define VIRTIO_PCI_CAP_LENGTH 12 /* Length of the structure, in bytes. */ + +struct virtio_dev_common { + le32 dev_features_sel; + le32 dev_features; + le32 drv_features_sel; + le32 drv_features; + le16 msix_config; + le16 num_queues; + uint8_t dev_status; + uint8_t cfg_generation; + + le16 q_select; + le16 q_size; + le16 q_msix_vec; + le16 q_enable; + le16 q_notify_off; + le64 q_desc; + le64 q_avail; + le64 q_used; +} __attribute__ ((packed)); + +/* virtio 1.0 Spec: 4.1.3 PCI Device Layout + * + * Fields of different sizes are present in the device configuration regions. + * All 64-bit, 32-bit and 16-bit fields are little-endian. 64-bit fields are to + * be treated as two 32-bit fields, with low 32 bit part followed by the high 32 + * bit part. + */ +static void virtio_pci_write64(void *addr, uint64_t val) +{ + uint32_t hi = (val >> 32) & 0xFFFFFFFF; + uint32_t lo = val & 0xFFFFFFFF; + + ci_write_32(addr, cpu_to_le32(lo)); + ci_write_32(addr + 4, cpu_to_le32(hi)); +} + +static uint64_t virtio_pci_read64(void *addr) +{ + uint64_t hi, lo; + + lo = le32_to_cpu(ci_read_32(addr)); + hi = le32_to_cpu(ci_read_32(addr + 4)); + return (hi << 32) | lo; +} + +static void virtio_cap_set_base_addr(struct virtio_cap *cap, uint32_t offset) +{ + uint64_t addr; + + addr = SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * cap->bar); + if (addr & PCI_BASE_ADDR_SPACE_IO) { + addr = addr & PCI_BASE_ADDR_IO_MASK; + cap->is_io = 1; + } else { + if (addr & PCI_BASE_ADDR_SPACE_64BIT) + addr |= SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * (cap->bar + 1)) << 32; + addr = addr & PCI_BASE_ADDR_MEM_MASK; + cap->is_io = 0; + } + addr = (uint64_t)SLOF_translate_my_address((void *)addr); + cap->addr = (void *)addr + offset; +} + +static void virtio_process_cap(struct virtio_device *dev, uint8_t cap_ptr) +{ + struct virtio_cap *cap; + uint8_t cfg_type, bar; + uint32_t offset; + + cfg_type = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_CFG_TYPE); + bar = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_BAR); + offset = SLOF_pci_config_read32(cap_ptr + VIRTIO_PCI_CAP_OFFSET); + + switch(cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + cap = &dev->common; + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + cap = &dev->notify; + dev->notify_off_mul = SLOF_pci_config_read32(cap_ptr + sizeof(struct virtio_cap)); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + cap = &dev->isr; + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + cap = &dev->device; + break; + default: + return; + } + + cap->bar = bar; + virtio_cap_set_base_addr(cap, offset); + cap->cap_id = cfg_type; +} + +/** + * Reads the virtio device capabilities, gets called from SLOF routines The + * function determines legacy or modern device and sets up driver registers + */ +struct virtio_device *virtio_setup_vd(void) +{ + uint8_t cap_ptr, cap_vndr; + struct virtio_device *dev; + + dev = SLOF_alloc_mem(sizeof(struct virtio_device)); + if (!dev) { + printf("Failed to allocate memory"); + return NULL; + } + + cap_ptr = SLOF_pci_config_read8(PCI_CONFIG_CAP_REG); + while (cap_ptr != 0) { + cap_vndr = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_VNDR); + if (cap_vndr == PCI_CAP_ID_VNDR) + virtio_process_cap(dev, cap_ptr); + cap_ptr = SLOF_pci_config_read8(cap_ptr+VIRTIO_PCI_CAP_NEXT); + } + + if (dev->common.cap_id && dev->notify.cap_id && + dev->isr.cap_id && dev->device.cap_id) { + dev->is_modern = 1; + } else { + dev->is_modern = 0; + dev->legacy.cap_id = 0; + dev->legacy.bar = 0; + virtio_cap_set_base_addr(&dev->legacy, 0); + } + return dev; +} /** * Calculate ring size according to queue size number @@ -33,9 +199,9 @@ unsigned long virtio_vring_size(unsigned int qsize) { return VQ_ALIGN(sizeof(struct vring_desc) * qsize + - sizeof(struct vring_avail) + sizeof(uint16_t) * qsize) + - VQ_ALIGN(sizeof(struct vring_used) + - sizeof(struct vring_used_elem) * qsize); + sizeof(struct vring_avail) + sizeof(uint16_t) * qsize) + + VQ_ALIGN(sizeof(struct vring_used) + + sizeof(struct vring_used_elem) * qsize); } @@ -45,15 +211,22 @@ unsigned long virtio_vring_size(unsigned int qsize) * @param queue virtio queue number * @return number of elements */ -int virtio_get_qsize(struct virtio_device *dev, int queue) +unsigned int virtio_get_qsize(struct virtio_device *dev, int queue) { - int size = 0; + unsigned int size = 0; - if (dev->type == VIRTIO_TYPE_PCI) { - ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT, + if (dev->is_modern) { + void *addr = dev->common.addr + offset_of(struct virtio_dev_common, q_select); + ci_write_16(addr, cpu_to_le16(queue)); + eieio(); + addr = dev->common.addr + offset_of(struct virtio_dev_common, q_size); + size = le16_to_cpu(ci_read_16(addr)); + } + else { + ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT, cpu_to_le16(queue)); eieio(); - size = le16_to_cpu(ci_read_16(dev->base+VIRTIOHDR_QUEUE_SIZE)); + size = le16_to_cpu(ci_read_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SIZE)); } return size; @@ -70,12 +243,19 @@ struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue) { struct vring_desc *desc = 0; - if (dev->type == VIRTIO_TYPE_PCI) { - ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT, + if (dev->is_modern) { + void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select); + void *q_desc = dev->common.addr + offset_of(struct virtio_dev_common, q_desc); + + ci_write_16(q_sel, cpu_to_le16(queue)); + eieio(); + desc = (void *)(virtio_pci_read64(q_desc)); + } else { + ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT, cpu_to_le16(queue)); eieio(); desc = (void*)(4096L * - le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS))); + le32_to_cpu(ci_read_32(dev->legacy.addr+VIRTIOHDR_QUEUE_ADDRESS))); } return desc; @@ -90,8 +270,18 @@ struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue) */ struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue) { - return (void*)((uint64_t)virtio_get_vring_desc(dev, queue) - + virtio_get_qsize(dev, queue) * sizeof(struct vring_desc)); + if (dev->is_modern) { + void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select); + void *q_avail = dev->common.addr + offset_of(struct virtio_dev_common, q_avail); + + ci_write_16(q_sel, cpu_to_le16(queue)); + eieio(); + return (void *)(virtio_pci_read64(q_avail)); + } + else { + return (void*)((uint64_t)virtio_get_vring_desc(dev, queue) + + virtio_get_qsize(dev, queue) * sizeof(struct vring_desc)); + } } @@ -103,20 +293,46 @@ struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue) */ struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue) { - return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue) - + virtio_get_qsize(dev, queue) - * sizeof(struct vring_avail)); + if (dev->is_modern) { + void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select); + void *q_used = dev->common.addr + offset_of(struct virtio_dev_common, q_used); + + ci_write_16(q_sel, cpu_to_le16(queue)); + eieio(); + return (void *)(virtio_pci_read64(q_used)); + } else { + return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue) + + virtio_get_qsize(dev, queue) + * sizeof(struct vring_avail)); + } } +/** + * Fill the virtio ring descriptor depending on the legacy mode or virtio 1.0 + */ +void virtio_fill_desc(struct vring_desc *desc, bool is_modern, + uint64_t addr, uint32_t len, + uint16_t flags, uint16_t next) +{ + if (is_modern) { + desc->addr = cpu_to_le64(addr); + desc->len = cpu_to_le32(len); + desc->flags = cpu_to_le16(flags); + desc->next = cpu_to_le16(next); + } else { + desc->addr = addr; + desc->len = len; + desc->flags = flags; + desc->next = next; + } +} /** * Reset virtio device */ void virtio_reset_device(struct virtio_device *dev) { - if (dev->type == VIRTIO_TYPE_PCI) { - ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, 0); - } + virtio_set_status(dev, 0); } @@ -125,25 +341,64 @@ void virtio_reset_device(struct virtio_device *dev) */ void virtio_queue_notify(struct virtio_device *dev, int queue) { - if (dev->type == VIRTIO_TYPE_PCI) { - ci_write_16(dev->base+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue)); + if (dev->is_modern) { + void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select); + void *q_ntfy = dev->common.addr + offset_of(struct virtio_dev_common, q_notify_off); + void *addr; + uint16_t q_notify_off; + + ci_write_16(q_sel, cpu_to_le16(queue)); + eieio(); + q_notify_off = le16_to_cpu(ci_read_16(q_ntfy)); + addr = dev->notify.addr + q_notify_off * dev->notify_off_mul; + ci_write_16(addr, cpu_to_le16(queue)); + } else { + ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue)); } } /** * Set queue address */ -void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr) +void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned long qaddr) +{ + if (dev->is_modern) { + uint64_t q_desc = qaddr; + uint64_t q_avail; + uint64_t q_used; + uint32_t q_size = virtio_get_qsize(dev, queue); + + virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_desc), q_desc); + q_avail = q_desc + q_size * sizeof(struct vring_desc); + virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_avail), q_avail); + q_used = VQ_ALIGN(q_avail + sizeof(struct vring_avail) + sizeof(uint16_t) * q_size); + virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_used), q_used); + ci_write_16(dev->common.addr + offset_of(struct virtio_dev_common, q_enable), cpu_to_le16(1)); + } else { + uint32_t val = qaddr; + val = val >> 12; + ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT, + cpu_to_le16(queue)); + eieio(); + ci_write_32(dev->legacy.addr+VIRTIOHDR_QUEUE_ADDRESS, + cpu_to_le32(val)); + } +} + +int virtio_queue_init_vq(struct virtio_device *dev, struct vqs *vq, unsigned int id) { - if (dev->type == VIRTIO_TYPE_PCI) { - uint32_t val = qaddr; - val = val >> 12; - ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT, - cpu_to_le16(queue)); - eieio(); - ci_write_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS, - cpu_to_le32(val)); - } + vq->size = virtio_get_qsize(dev, id); + vq->desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq->size), 4096); + if (!vq->desc) { + printf("memory allocation failed!\n"); + return -1; + } + memset(vq->desc, 0, virtio_vring_size(vq->size)); + virtio_set_qaddr(dev, id, (unsigned long)vq->desc); + vq->avail = virtio_get_vring_avail(dev, id); + vq->used = virtio_get_vring_used(dev, id); + vq->id = id; + return 0; } /** @@ -151,34 +406,109 @@ void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr) */ void virtio_set_status(struct virtio_device *dev, int status) { - if (dev->type == VIRTIO_TYPE_PCI) { - ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, status); + if (dev->is_modern) { + ci_write_8(dev->common.addr + + offset_of(struct virtio_dev_common, dev_status), status); + } else { + ci_write_8(dev->legacy.addr+VIRTIOHDR_DEVICE_STATUS, status); } } +/** + * Get device status bits + */ +void virtio_get_status(struct virtio_device *dev, int *status) +{ + if (dev->is_modern) { + *status = ci_read_8(dev->common.addr + + offset_of(struct virtio_dev_common, dev_status)); + } else { + *status = ci_read_8(dev->legacy.addr+VIRTIOHDR_DEVICE_STATUS); + } +} /** * Set guest feature bits */ -void virtio_set_guest_features(struct virtio_device *dev, int features) +void virtio_set_guest_features(struct virtio_device *dev, uint64_t features) { - if (dev->type == VIRTIO_TYPE_PCI) { - ci_write_32(dev->base+VIRTIOHDR_GUEST_FEATURES, bswap_32(features)); + if (dev->is_modern) { + uint32_t f1 = (features >> 32) & 0xFFFFFFFF; + uint32_t f0 = features & 0xFFFFFFFF; + void *addr = dev->common.addr; + + ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features_sel), + cpu_to_le32(1)); + ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features), + cpu_to_le32(f1)); + + ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features_sel), + cpu_to_le32(0)); + ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features), + cpu_to_le32(f0)); + } else { + ci_write_32(dev->legacy.addr+VIRTIOHDR_GUEST_FEATURES, cpu_to_le32(features)); } } /** * Get host feature bits */ -void virtio_get_host_features(struct virtio_device *dev, int *features) +uint64_t virtio_get_host_features(struct virtio_device *dev) { - if (dev->type == VIRTIO_TYPE_PCI && features) { - *features = bswap_32(ci_read_32(dev->base+VIRTIOHDR_DEVICE_FEATURES)); + uint64_t features = 0; + if (dev->is_modern) { + uint32_t f0 = 0, f1 = 0; + void *addr = dev->common.addr; + + ci_write_32(addr + offset_of(struct virtio_dev_common, dev_features_sel), + cpu_to_le32(1)); + f1 = ci_read_32(addr + + offset_of(struct virtio_dev_common, dev_features)); + ci_write_32(addr + offset_of(struct virtio_dev_common, dev_features_sel), + cpu_to_le32(0)); + f0 = ci_read_32(addr + + offset_of(struct virtio_dev_common, dev_features)); + + features = ((uint64_t)le32_to_cpu(f1) << 32) | le32_to_cpu(f0); + } else { + features = le32_to_cpu(ci_read_32(dev->legacy.addr+VIRTIOHDR_DEVICE_FEATURES)); } + return features; } +int virtio_negotiate_guest_features(struct virtio_device *dev, uint64_t features) +{ + uint64_t host_features = 0; + int status; + + /* Negotiate features */ + host_features = virtio_get_host_features(dev); + if (!(host_features & VIRTIO_F_VERSION_1)) { + fprintf(stderr, "Device does not support virtio 1.0 %llx\n", host_features); + return -1; + } + + virtio_set_guest_features(dev, features); + host_features = virtio_get_host_features(dev); + if ((host_features & features) != features) { + fprintf(stderr, "Features error %llx\n", features); + return -1; + } + + virtio_get_status(dev, &status); + status |= VIRTIO_STAT_FEATURES_OK; + virtio_set_status(dev, status); + + /* Read back to verify the FEATURES_OK bit */ + virtio_get_status(dev, &status); + if ((status & VIRTIO_STAT_FEATURES_OK) != VIRTIO_STAT_FEATURES_OK) + return -1; + + return 0; +} /** * Get additional config values @@ -186,32 +516,38 @@ void virtio_get_host_features(struct virtio_device *dev, int *features) uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size) { uint64_t val = ~0ULL; + uint32_t hi, lo; void *confbase; - switch (dev->type) { - case VIRTIO_TYPE_PCI: - confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG; - break; - default: - return ~0ULL; - } + if (dev->is_modern) + confbase = dev->device.addr; + else + confbase = dev->legacy.addr+VIRTIOHDR_DEVICE_CONFIG; + switch (size) { - case 1: + case 1: val = ci_read_8(confbase+offset); break; - case 2: + case 2: val = ci_read_16(confbase+offset); + if (dev->is_modern) + val = le16_to_cpu(val); break; - case 4: + case 4: val = ci_read_32(confbase+offset); + if (dev->is_modern) + val = le32_to_cpu(val); break; - case 8: + case 8: /* We don't support 8 bytes PIO accesses * in qemu and this is all PIO */ - val = ci_read_32(confbase+offset); - val <<= 32; - val |= ci_read_32(confbase+offset+4); + lo = ci_read_32(confbase+offset); + hi = ci_read_32(confbase+offset+4); + if (dev->is_modern) + val = (uint64_t)le32_to_cpu(hi) << 32 | le32_to_cpu(lo); + else + val = (uint64_t)hi << 32 | lo; break; } @@ -222,20 +558,19 @@ uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size) * Get config blob */ int __virtio_read_config(struct virtio_device *dev, void *dst, - int offset, int len) + int offset, int len) { void *confbase; unsigned char *buf = dst; int i; - switch (dev->type) { - case VIRTIO_TYPE_PCI: - confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG; - break; - default: - return 0; - } + if (dev->is_modern) + confbase = dev->device.addr; + else + confbase = dev->legacy.addr+VIRTIOHDR_DEVICE_CONFIG; + for (i = 0; i < len; i++) buf[i] = ci_read_8(confbase + offset + i); + return len; } diff --git a/roms/SLOF/lib/libvirtio/virtio.code b/roms/SLOF/lib/libvirtio/virtio.code index 258b9bbda..8eec8f055 100644 --- a/roms/SLOF/lib/libvirtio/virtio.code +++ b/roms/SLOF/lib/libvirtio/virtio.code @@ -18,6 +18,11 @@ /******** core virtio ********/ +// : virtio-setup-vd ( -- dev ) +PRIM(virtio_X2d_setup_X2d_vd) + PUSH; TOS.a = virtio_setup_vd(); +MIRP + // : virtio-vring-size ( queuesize -- ringsize ) PRIM(virtio_X2d_vring_X2d_size) TOS.u = virtio_vring_size(TOS.u); @@ -122,20 +127,18 @@ MIRP /******** virtio-net ********/ -// : virtio-net-open ( mac-addr-str len dev -- false | [ driver true ] ) +// : virtio-net-open ( dev -- false | [ driver true ] ) PRIM(virtio_X2d_net_X2d_open) { - void *dev = TOS.a; POP; - int len = TOS.u; POP; - char *mac_addr = TOS.a; + void *dev = TOS.a; - net_driver_t *net_driver = virtionet_open(mac_addr, len, dev); + net_driver_t *net_driver = virtionet_open(dev); - if (net_driver) { - TOS.u = (unsigned long)net_driver; PUSH; - TOS.n = -1; - } else - TOS.n = 0; + if (net_driver) { + TOS.u = (unsigned long)net_driver; PUSH; + TOS.n = -1; + } else + TOS.n = 0; } MIRP diff --git a/roms/SLOF/lib/libvirtio/virtio.h b/roms/SLOF/lib/libvirtio/virtio.h index d5759b45a..0fee4baec 100644 --- a/roms/SLOF/lib/libvirtio/virtio.h +++ b/roms/SLOF/lib/libvirtio/virtio.h @@ -14,13 +14,23 @@ #define _LIBVIRTIO_H #include <stdint.h> +#include <stdbool.h> /* Device status bits */ #define VIRTIO_STAT_ACKNOWLEDGE 1 #define VIRTIO_STAT_DRIVER 2 #define VIRTIO_STAT_DRIVER_OK 4 +#define VIRTIO_STAT_FEATURES_OK 8 +#define VIRTIO_STAT_NEEDS_RESET 64 #define VIRTIO_STAT_FAILED 128 +#define BIT(x) (1UL << (x)) + +/* VIRTIO 1.0 Device independent feature bits */ +#define VIRTIO_F_RING_INDIRECT_DESC BIT(28) +#define VIRTIO_F_RING_EVENT_IDX BIT(29) +#define VIRTIO_F_VERSION_1 BIT(32) + #define VIRTIO_TIMEOUT 5000 /* 5 sec timeout */ /* Definitions for vring_desc.flags */ @@ -34,7 +44,7 @@ struct vring_desc { uint32_t len; /* Length */ uint16_t flags; /* The flags as indicated above */ uint16_t next; /* Next field if flags & NEXT */ -}; +}; /* Definitions for vring_avail.flags */ #define VRING_AVAIL_F_NO_INTERRUPT 1 @@ -44,8 +54,7 @@ struct vring_avail { uint16_t flags; uint16_t idx; uint16_t ring[]; -}; - +}; /* Definitions for vring_used.flags */ #define VRING_USED_F_NO_NOTIFY 1 @@ -61,27 +70,56 @@ struct vring_used { struct vring_used_elem ring[]; }; -#define VIRTIO_TYPE_PCI 0 /* For virtio-pci interface */ +/* Structure shared with SLOF and is 16bytes */ +struct virtio_cap { + void *addr; + uint8_t bar; + uint8_t is_io; + uint8_t cap_id; +}; + struct virtio_device { - void *base; /* base address */ - int type; /* VIRTIO_TYPE_PCI or VIRTIO_TYPE_VIO */ + uint32_t is_modern; /* Indicates whether to use virtio 1.0 */ + struct virtio_cap legacy; + struct virtio_cap common; + struct virtio_cap notify; + struct virtio_cap isr; + struct virtio_cap device; + struct virtio_cap pci; + uint32_t notify_off_mul; +}; + +struct vqs { + uint64_t id; /* Queue ID */ + uint32_t size; + void *buf_mem; + struct vring_desc *desc; + struct vring_avail *avail; + struct vring_used *used; }; /* Parts of the virtqueue are aligned on a 4096 byte page boundary */ #define VQ_ALIGN(addr) (((addr) + 0xfff) & ~0xfff) extern unsigned long virtio_vring_size(unsigned int qsize); -extern int virtio_get_qsize(struct virtio_device *dev, int queue); +extern unsigned int virtio_get_qsize(struct virtio_device *dev, int queue); extern struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue); extern struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue); extern struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue); +extern void virtio_fill_desc(struct vring_desc *desc, bool is_modern, + uint64_t addr, uint32_t len, + uint16_t flags, uint16_t next); +extern int virtio_queue_init_vq(struct virtio_device *dev, struct vqs *vq, unsigned int id); +extern struct virtio_device *virtio_setup_vd(void); extern void virtio_reset_device(struct virtio_device *dev); extern void virtio_queue_notify(struct virtio_device *dev, int queue); extern void virtio_set_status(struct virtio_device *dev, int status); -extern void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr); -extern void virtio_set_guest_features(struct virtio_device *dev, int features); -extern void virtio_get_host_features(struct virtio_device *dev, int *features); +extern void virtio_get_status(struct virtio_device *dev, int *status); +extern void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned long qaddr); +extern void virtio_set_guest_features(struct virtio_device *dev, uint64_t features); +extern uint64_t virtio_get_host_features(struct virtio_device *dev); +extern int virtio_negotiate_guest_features(struct virtio_device *dev, uint64_t features); extern uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size); extern int __virtio_read_config(struct virtio_device *dev, void *dst, int offset, int len); diff --git a/roms/SLOF/lib/libvirtio/virtio.in b/roms/SLOF/lib/libvirtio/virtio.in index c36d127c7..195840e0f 100644 --- a/roms/SLOF/lib/libvirtio/virtio.in +++ b/roms/SLOF/lib/libvirtio/virtio.in @@ -10,6 +10,8 @@ * IBM Corporation - initial implementation *****************************************************************************/ +cod(virtio-setup-vd) + cod(virtio-vring-size) cod(virtio-get-qsize) cod(virtio-get-config) diff --git a/roms/SLOF/slof/entry.S b/roms/SLOF/slof/entry.S index d3d29f852..5372de357 100644 --- a/roms/SLOF/slof/entry.S +++ b/roms/SLOF/slof/entry.S @@ -215,5 +215,5 @@ C_ENTRY(call_c) mtctr r6 bctr - +.global the_system_stack .lcomm the_system_stack, STACKSIZE, 16 diff --git a/roms/SLOF/slof/fs/boot.fs b/roms/SLOF/slof/fs/boot.fs index a0fe29a1b..e0b628140 100644 --- a/roms/SLOF/slof/fs/boot.fs +++ b/roms/SLOF/slof/fs/boot.fs @@ -181,6 +181,7 @@ defer go ( -- ) \ with watchdog timeout. 4ec set-watchdog THEN + 2dup " HALT" str= IF 2drop 0 EXIT THEN my-self >r current-node @ >r \ Save my-self ." Trying to load: " $bootargs type ." from: " 2dup type ." ... " 2dup open-dev dup IF diff --git a/roms/SLOF/slof/fs/packages/fat-files.fs b/roms/SLOF/slof/fs/packages/fat-files.fs index 0cec3664e..d9194527e 100644 --- a/roms/SLOF/slof/fs/packages/fat-files.fs +++ b/roms/SLOF/slof/fs/packages/fat-files.fs @@ -18,6 +18,7 @@ INSTANCE VARIABLE sectors/cluster INSTANCE VARIABLE #reserved-sectors INSTANCE VARIABLE #fats INSTANCE VARIABLE #root-entries +INSTANCE VARIABLE fat32-root-cluster INSTANCE VARIABLE total-#sectors INSTANCE VARIABLE media-descriptor INSTANCE VARIABLE sectors/fat @@ -59,9 +60,18 @@ INSTANCE VARIABLE next-cluster : read-cluster ( cluster# -- ) dup bytes/cluster @ * cluster-offset @ + bytes/cluster @ read-data read-fat dup #clusters @ >= IF drop 0 THEN next-cluster ! ; + : read-dir ( cluster# -- ) - ?dup 0= IF root-offset @ #root-entries @ 20 * read-data 0 next-cluster ! - ELSE read-cluster THEN ; + ?dup 0= IF + #root-entries @ 0= IF + fat32-root-cluster @ read-cluster + ELSE + root-offset @ #root-entries @ 20 * read-data 0 next-cluster ! + THEN + ELSE + read-cluster + THEN +; : .time ( x -- ) base @ >r decimal @@ -137,6 +147,7 @@ CREATE dos-name b allot \ For FAT32: sectors/fat @ 0= IF data @ 24 + 4c@ bljoin sectors/fat ! THEN + #root-entries @ 0= IF data @ 2c + 4c@ bljoin ELSE 0 THEN fat32-root-cluster ! \ XXX add other FAT32 stuff (offsets 28, 2c, 30) diff --git a/roms/SLOF/slof/fs/pci-config-bridge.fs b/roms/SLOF/slof/fs/pci-config-bridge.fs index 689325318..1efbcd804 100644 --- a/roms/SLOF/slof/fs/pci-config-bridge.fs +++ b/roms/SLOF/slof/fs/pci-config-bridge.fs @@ -81,26 +81,6 @@ 2drop ; -: dma-alloc ( ... size -- virt ) - \ ." dma-alloc called: " .s cr - alloc-mem -; - -: dma-free ( virt size -- ) - \ ." dma-free called: " .s cr - free-mem -; - -: dma-map-in ( ... virt size cacheable? -- devaddr ) - \ ." dma-map-in called: " .s cr - 2drop -; - -: dma-map-out ( virt devaddr size -- ) - \ ." dma-map-out called: " .s cr - 2drop drop -; - : dma-sync ( virt devaddr size -- ) \ XXX should we add at least a memory barrier here? \ ." dma-sync called: " .s cr diff --git a/roms/SLOF/slof/fs/root.fs b/roms/SLOF/slof/fs/root.fs index 21c710951..952b00e75 100644 --- a/roms/SLOF/slof/fs/root.fs +++ b/roms/SLOF/slof/fs/root.fs @@ -77,7 +77,6 @@ finish-device : open true ; : close ; -#include <archsupport.fs> \ Finish root finish-device diff --git a/roms/SLOF/slof/helpers.c b/roms/SLOF/slof/helpers.c index d7c1888b4..48c34a65c 100644 --- a/roms/SLOF/slof/helpers.c +++ b/roms/SLOF/slof/helpers.c @@ -114,6 +114,13 @@ long SLOF_pci_config_read16(long offset) return forth_pop(); } +long SLOF_pci_config_read8(long offset) +{ + forth_push(offset); + forth_eval("config-b@"); + return forth_pop(); +} + void SLOF_pci_config_write32(long offset, long value) { forth_push(value); @@ -128,6 +135,13 @@ void SLOF_pci_config_write16(long offset, long value) forth_eval("config-w!"); } +void SLOF_pci_config_write8(long offset, long value) +{ + forth_push(value); + forth_push(offset); + forth_eval("config-b!"); +} + void *SLOF_translate_my_address(void *addr) { forth_push((long)addr); diff --git a/roms/SLOF/slof/paflof.c b/roms/SLOF/slof/paflof.c index 624955fba..2fc25c81e 100644 --- a/roms/SLOF/slof/paflof.c +++ b/roms/SLOF/slof/paflof.c @@ -19,6 +19,7 @@ #undef unix #include "paflof.h" +#include <stdio.h> #include <string.h> #include <stdint.h> #include <ctype.h> @@ -43,6 +44,9 @@ unsigned char hash_table[HASHSIZE*CELLSIZE]; #include ISTR(TARG,c) +static int did_stackwarning; +extern char the_system_stack[]; + // the actual engine long engine(int mode, long param_1, long param_2) { @@ -84,6 +88,11 @@ long engine(int mode, long param_1, long param_2) c_return[1].a = &dummy; } + if ((char *)&ip < the_system_stack && !did_stackwarning) { + puts("ERROR: stack overflow in engine()!"); + did_stackwarning = 1; + } + if (mode & ENGINE_MODE_PARAM_2) { (++dp)->n = param_2; } diff --git a/roms/config.seabios-128k b/roms/config.seabios-128k index c719ba689..0a9da77a5 100644 --- a/roms/config.seabios-128k +++ b/roms/config.seabios-128k @@ -3,6 +3,8 @@ CONFIG_QEMU=y CONFIG_ROM_SIZE=128 CONFIG_XEN=n +CONFIG_USB_OHCI=n CONFIG_USB_XHCI=n CONFIG_USB_UAS=n CONFIG_SDCARD=n +CONFIG_TCGBIOS=n diff --git a/roms/openbios/Makefile.target b/roms/openbios/Makefile.target index a7363e667..4c54105a7 100644 --- a/roms/openbios/Makefile.target +++ b/roms/openbios/Makefile.target @@ -15,7 +15,7 @@ HOSTCFLAGS+= -Wstrict-aliasing -Wwrite-strings -Wmissing-prototypes -Wnested-ext HOSTCFLAGS+= -W # Flags for dependency generation HOSTCFLAGS+= -MMD -MP -MT $@ -MF '$(*D)/$(*F).d' -HOSTINCLUDES := -I$(SRCDIR)/include -I$(SRCDIR)/kernel -I$(SRCDIR)/kernel/include -I$(ODIR)/target/include +HOSTINCLUDES := -I$(SRCDIR)/include -I$(SRCDIR)/kernel -I$(SRCDIR)/kernel/include -iquote $(ODIR)/target/include CC := $(TARGET)gcc AS := $(TARGET)as diff --git a/roms/openbios/arch/ppc/qemu/init.c b/roms/openbios/arch/ppc/qemu/init.c index 2b5b8e1a9..b76c5706f 100644 --- a/roms/openbios/arch/ppc/qemu/init.c +++ b/roms/openbios/arch/ppc/qemu/init.c @@ -601,6 +601,11 @@ go(void) { ucell addr; + /* Insert copyright property for MacOS 9 and below */ + if (find_dev("/rom/macos")) { + fword("insert-copyright-property"); + } + feval("saved-program-state >sps.entry @"); addr = POP(); diff --git a/roms/openbios/arch/ppc/qemu/qemu.fs b/roms/openbios/arch/ppc/qemu/qemu.fs index 11e344a59..3d99a34a1 100644 --- a/roms/openbios/arch/ppc/qemu/qemu.fs +++ b/roms/openbios/arch/ppc/qemu/qemu.fs @@ -95,15 +95,13 @@ variable keyboard-phandle 0 keyboard-phandle ! ; PREPOST-initializer \ ------------------------------------------------------------------------- -\ Adler-32 wrapper +\ copyright property handling \ ------------------------------------------------------------------------- -: adler32 ( adler buf len -- checksum ) - \ Since Mac OS 9 is the only system using this word, we take this - \ opportunity to inject a copyright message that is necessary for the - \ system to boot. - " Copyright 1983-2001 Apple Computer, Inc. THIS MESSAGE FOR COMPATIBILITY ONLY" - encode-string " copyright" +: insert-copyright-property + \ As required for MacOS 9 and below + " Pbclevtug 1983-2001 Nccyr Pbzchgre, Vap. GUVF ZRFFNTR SBE PBZCNGVOVYVGL BAYL" + rot13-str encode-string " copyright" " /" find-package if " set-property" $find if execute @@ -111,9 +109,28 @@ variable keyboard-phandle 0 keyboard-phandle ! 3drop drop then then +; - ( adler buf len ) +: delete-copyright-property + \ Remove copyright property created above + active-package + " /" find-package if + active-package! + " copyright" delete-property + then + active-package! +; +: (exit) + \ Clean up before returning to the interpreter + delete-copyright-property +; + +\ ------------------------------------------------------------------------- +\ Adler-32 wrapper +\ ------------------------------------------------------------------------- + +: adler32 ( adler buf len -- checksum ) " (adler32)" $find if execute else diff --git a/roms/openbios/arch/sparc64/call-client.S b/roms/openbios/arch/sparc64/call-client.S index f365e3cb1..a8c0348e4 100644 --- a/roms/openbios/arch/sparc64/call-client.S +++ b/roms/openbios/arch/sparc64/call-client.S @@ -1,3 +1,5 @@ +#include "cpustate.h" + .globl sparc64_of_client_interface, client_tba @@ -9,151 +11,9 @@ * behaviour of OBP. */ -#define SAVE_WINDOW_STATE(type) \ - setx client_window, %g6, %g1; \ - rdpr %cwp, %g7; \ - stx %g7, [%g1]; \ - rdpr %cansave, %g7; \ - stx %g7, [%g1 + 0x8]; \ - rdpr %canrestore, %g7; \ - stx %g7, [%g1 + 0x10]; \ - rdpr %otherwin, %g7; \ - stx %g7, [%g1 + 0x18]; \ - rdpr %wstate, %g7; \ - stx %g7, [%g1 + 0x20]; \ - rdpr %cleanwin, %g7; \ - stx %g7, [%g1 + 0x28]; \ - \ - stx %o0, [%g1 + 0x30]; \ - stx %o1, [%g1 + 0x38]; \ - stx %o2, [%g1 + 0x40]; \ - stx %o3, [%g1 + 0x48]; \ - stx %o4, [%g1 + 0x50]; \ - stx %o5, [%g1 + 0x58]; \ - stx %o6, [%g1 + 0x60]; \ - stx %o7, [%g1 + 0x68]; \ - \ - rdpr %pstate, %g7; \ - stx %g7, [%g1 + 0x70]; \ - rd %y, %g7; \ - stx %g7, [%g1 + 0x78]; \ - rd %fprs, %g7; \ - stx %g7, [%g1 + 0x80]; \ - \ - /* Now iterate through all of the windows saving all l and i registers */ \ - add %g1, 0x90, %g5; \ - \ - /* Get the number of windows in %g6 */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - inc %g6; \ - \ -save_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ - stx %l0, [%g5]; \ - stx %l1, [%g5 + 0x8]; \ - stx %l2, [%g5 + 0x10]; \ - stx %l3, [%g5 + 0x18]; \ - stx %l4, [%g5 + 0x20]; \ - stx %l5, [%g5 + 0x28]; \ - stx %l6, [%g5 + 0x30]; \ - stx %l7, [%g5 + 0x38]; \ - stx %i0, [%g5 + 0x40]; \ - stx %i1, [%g5 + 0x48]; \ - stx %i2, [%g5 + 0x50]; \ - stx %i3, [%g5 + 0x58]; \ - stx %i4, [%g5 + 0x60]; \ - stx %i5, [%g5 + 0x68]; \ - stx %i6, [%g5 + 0x70]; \ - stx %i7, [%g5 + 0x78]; \ - bne save_cpu_window_##type; \ - add %g5, 0x80, %g5; \ - \ - /* For 8 windows with 16 registers to save in the window, memory required \ - is 16*8*8 = 0x400 bytes */ \ - \ - /* Now we should be in window 0 so update the other window registers */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - dec %g6; \ - wrpr %g6, %cansave; \ - \ - wrpr %g0, %cleanwin; \ - wrpr %g0, %canrestore; \ - wrpr %g0, %otherwin; - - -#define RESTORE_WINDOW_STATE(type) \ - setx client_window, %g6, %g1; \ - \ - /* Get the number of windows in %g6 */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - inc %g6; \ - \ - /* Now iterate through all of the windows restoring all l and i registers */ \ - add %g1, 0x90, %g5; \ - \ -restore_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ - ldx [%g5], %l0; \ - ldx [%g5 + 0x8], %l1; \ - ldx [%g5 + 0x10], %l2; \ - ldx [%g5 + 0x18], %l3; \ - ldx [%g5 + 0x20], %l4; \ - ldx [%g5 + 0x28], %l5; \ - ldx [%g5 + 0x30], %l6; \ - ldx [%g5 + 0x38], %l7; \ - ldx [%g5 + 0x40], %i0; \ - ldx [%g5 + 0x48], %i1; \ - ldx [%g5 + 0x50], %i2; \ - ldx [%g5 + 0x58], %i3; \ - ldx [%g5 + 0x60], %i4; \ - ldx [%g5 + 0x68], %i5; \ - ldx [%g5 + 0x70], %i6; \ - ldx [%g5 + 0x78], %i7; \ - bne restore_cpu_window_##type; \ - add %g5, 0x80, %g5; \ - \ - /* Restore the window registers to their original value */ \ - ldx [%g1], %g7; \ - wrpr %g7, %cwp; \ - ldx [%g1 + 0x8], %g7; \ - wrpr %g7, %cansave; \ - ldx [%g1 + 0x10], %g7; \ - wrpr %g7, %canrestore; \ - ldx [%g1 + 0x18], %g7; \ - wrpr %g7, %otherwin; \ - ldx [%g1 + 0x20], %g7; \ - wrpr %g7, %wstate; \ - ldx [%g1 + 0x28], %g7; \ - wrpr %g7, %cleanwin; \ - \ - ldx [%g1 + 0x30], %o0; \ - ldx [%g1 + 0x38], %o1; \ - ldx [%g1 + 0x40], %o2; \ - ldx [%g1 + 0x48], %o3; \ - ldx [%g1 + 0x50], %o4; \ - ldx [%g1 + 0x58], %o5; \ - ldx [%g1 + 0x60], %o6; \ - ldx [%g1 + 0x68], %o7; \ - \ - ldx [%g1 + 0x70], %g7; \ - wrpr %g7, %pstate; \ - ldx [%g1 + 0x78], %g7; \ - wr %g7, 0, %y; \ - ldx [%g1 + 0x80], %g7; \ - wr %g7, 0, %fprs - - .data .align 8 - .skip 16384 -openbios_stack: - client_stack: .xword 0 client_tba: @@ -176,15 +36,15 @@ client_window: sparc64_of_client_interface: /* Save globals on callers stack */ - add %sp, -56, %sp + add %sp, -248, %sp - stx %g1, [%sp + 2047 + 0] - stx %g2, [%sp + 2047 + 8] - stx %g3, [%sp + 2047 + 16] - stx %g4, [%sp + 2047 + 24] - stx %g5, [%sp + 2047 + 32] - stx %g6, [%sp + 2047 + 40] - stx %g7, [%sp + 2047 + 48] + stx %g1, [%sp + 2047 + 192] + stx %g2, [%sp + 2047 + 200] + stx %g3, [%sp + 2047 + 208] + stx %g4, [%sp + 2047 + 216] + stx %g5, [%sp + 2047 + 224] + stx %g6, [%sp + 2047 + 232] + stx %g7, [%sp + 2047 + 240] /* Save client trap table */ setx client_tba, %g6, %g7 @@ -196,22 +56,44 @@ sparc64_of_client_interface: stx %sp, [%g7] /* Save windows */ - SAVE_WINDOW_STATE(cif) - - /* Move to OpenBIOS stack */ - setx openbios_stack - 2047 - 192, %g6, %g7 + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, -CONTEXT_STATE_SIZE, %g1 + stx %g1, [%g7] + + SAVE_CPU_WINDOW_STATE(cif) + + /* Move to OpenBIOS context stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g6 + setx CONTEXT_STACK_SIZE, %g4, %g5 + sub %g6, %g5, %g6 + stx %g6, [%g7] + + setx - 2047 - 192, %g6, %g7 + add %g1, %g7, %g7 mov %g7, %sp /* Call client inteface */ call of_client_interface ldx [%g1 + 0x30], %o0 - setx client_window, %g6, %g1 - stx %o0, [%g1 + 0x30] - /* Restore windows */ - RESTORE_WINDOW_STATE(cif) - + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + setx CONTEXT_STACK_SIZE, %g4, %g5 + add %g1, %g5, %g1 + stx %g1, [%g7] + + /* Return value */ + stx %o0, [%g1 + 0x30] + + RESTORE_CPU_WINDOW_STATE(cif) + + add %g1, CONTEXT_STATE_SIZE, %g1 + setx _fcstack_ptr, %g6, %g7 + stx %g1, [%g7] + /* Restore stack */ setx client_stack, %g6, %g7 ldx [%g7], %sp @@ -222,15 +104,15 @@ sparc64_of_client_interface: wrpr %g6, %tba /* Restore globals */ - ldx [%sp + 2047 + 0], %g1 - ldx [%sp + 2047 + 8], %g2 - ldx [%sp + 2047 + 16], %g3 - ldx [%sp + 2047 + 24], %g4 - ldx [%sp + 2047 + 32], %g5 - ldx [%sp + 2047 + 40], %g6 - ldx [%sp + 2047 + 48], %g7 - - add %sp, 56, %sp + ldx [%sp + 2047 + 192], %g1 + ldx [%sp + 2047 + 200], %g2 + ldx [%sp + 2047 + 208], %g3 + ldx [%sp + 2047 + 216], %g4 + ldx [%sp + 2047 + 224], %g5 + ldx [%sp + 2047 + 232], %g6 + ldx [%sp + 2047 + 240], %g7 + + add %sp, 248, %sp jmp %o7+8 nop diff --git a/roms/openbios/arch/sparc64/context.c b/roms/openbios/arch/sparc64/context.c index 2e7668958..98932ee9c 100644 --- a/roms/openbios/arch/sparc64/context.c +++ b/roms/openbios/arch/sparc64/context.c @@ -40,6 +40,10 @@ static uint8_t image_stack[IMAGE_STACK_SIZE]; /* Pointer to startup context (physical address) */ unsigned long __boot_ctx; +/* Pointer to Forth context stack */ +void *_fcstack_ptr = &_efcstack; + + /* * Main starter * This is the C function that runs first. diff --git a/roms/openbios/arch/sparc64/cpustate.h b/roms/openbios/arch/sparc64/cpustate.h new file mode 100644 index 000000000..0c276bfd1 --- /dev/null +++ b/roms/openbios/arch/sparc64/cpustate.h @@ -0,0 +1,244 @@ +/* + * Save/restore CPU state macros + * + * Copyright (C) 2015 Mark Cave-Ayland (mark.cave-ayland@ilande.co.uk>) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +/* State size for context (see below) */ +#define CONTEXT_STATE_SIZE 0x510 + +/* Stack size for context (allocated inline of the context stack) */ +#define CONTEXT_STACK_SIZE 0x2000 + +/* + * SAVE_CPU_STATE and RESTORE_CPU_STATE are macros used to enable a context switch + * to C to occur within the MMU I/D TLB miss handlers. + * + * Because these handlers are called on a TLB miss, we cannot use flushw to store + * processor window state on the stack, as the memory areas used by each window's + * stack pointer may not be in the TLB, causing recursive TLB miss traps. + * + * For this reason, we save window state by manually rotating the window registers + * and saving their contents (along with other vital registers) into a special + * tlb_handler_stack defined above which is guaranteed to be locked in the TLB, and + * so won't cause issues with trap recursion. + * + * Once this process is complete, we remain in a TL=0, CWP=0 state (with IE=1 to allow + * window fill/spill traps if required), switch to our safe tlb_handler_stack and + * invoke the miss handler. + */ + +#define SAVE_CPU_WINDOW_STATE(type) \ + /* Save window state into context at %g1 */ \ + rdpr %cwp, %g7; \ + stx %g7, [%g1]; \ + rdpr %cansave, %g7; \ + stx %g7, [%g1 + 0x8]; \ + rdpr %canrestore, %g7; \ + stx %g7, [%g1 + 0x10]; \ + rdpr %otherwin, %g7; \ + stx %g7, [%g1 + 0x18]; \ + rdpr %wstate, %g7; \ + stx %g7, [%g1 + 0x20]; \ + rdpr %cleanwin, %g7; \ + stx %g7, [%g1 + 0x28]; \ + \ + stx %o0, [%g1 + 0x30]; \ + stx %o1, [%g1 + 0x38]; \ + stx %o2, [%g1 + 0x40]; \ + stx %o3, [%g1 + 0x48]; \ + stx %o4, [%g1 + 0x50]; \ + stx %o5, [%g1 + 0x58]; \ + stx %o6, [%g1 + 0x60]; \ + stx %o7, [%g1 + 0x68]; \ + \ + rdpr %pstate, %g7; \ + stx %g7, [%g1 + 0x70]; \ + rd %y, %g7; \ + stx %g7, [%g1 + 0x78]; \ + rd %fprs, %g7; \ + stx %g7, [%g1 + 0x80]; \ + rdpr %tl, %g7; \ + stx %g7, [%g1 + 0x88]; \ + \ + /* Now iterate through all of the windows saving all l and i registers */ \ + add %g1, 0x90, %g5; \ + \ + /* Get the number of windows in %g6 */ \ + rdpr %ver, %g6; \ + and %g6, 0xf, %g6; \ + \ + mov %g6, %g4; \ + inc %g4; \ + \ + /* Starting cwp in g7 */ \ + rdpr %cwp, %g7; \ + \ +save_cpu_window_##type: \ + wrpr %g7, %cwp; \ + stx %l0, [%g5]; \ + stx %l1, [%g5 + 0x8]; \ + stx %l2, [%g5 + 0x10]; \ + stx %l3, [%g5 + 0x18]; \ + stx %l4, [%g5 + 0x20]; \ + stx %l5, [%g5 + 0x28]; \ + stx %l6, [%g5 + 0x30]; \ + stx %l7, [%g5 + 0x38]; \ + stx %i0, [%g5 + 0x40]; \ + stx %i1, [%g5 + 0x48]; \ + stx %i2, [%g5 + 0x50]; \ + stx %i3, [%g5 + 0x58]; \ + stx %i4, [%g5 + 0x60]; \ + stx %i5, [%g5 + 0x68]; \ + stx %i6, [%g5 + 0x70]; \ + stx %i7, [%g5 + 0x78]; \ + dec %g7; \ + and %g7, %g6, %g7; \ + subcc %g4, 1, %g4; \ + bne save_cpu_window_##type; \ + add %g5, 0x80, %g5; \ + \ + /* For 8 windows with 16 registers to save in the window, memory required \ + is 16*8*8 = 0x400 bytes */ \ + \ + /* Now we should be in window 0 so update the other window registers */ \ + rdpr %ver, %g6; \ + and %g6, 0xf, %g6; \ + dec %g6; \ + wrpr %g6, %cansave; \ + \ + wrpr %g0, %cleanwin; \ + wrpr %g0, %canrestore; \ + wrpr %g0, %otherwin; \ + + +#define SAVE_CPU_TRAP_STATE(type) \ + /* Save trap state into context at %g1 */ \ + add %g1, 0x490, %g5; \ + mov 4, %g6; \ + \ +save_trap_state_##type: \ + deccc %g6; \ + wrpr %g6, %tl; \ + rdpr %tpc, %g7; \ + stx %g7, [%g5]; \ + rdpr %tnpc, %g7; \ + stx %g7, [%g5 + 0x8]; \ + rdpr %tstate, %g7; \ + stx %g7, [%g5 + 0x10]; \ + rdpr %tt, %g7; \ + stx %g7, [%g5 + 0x18]; \ + bne save_trap_state_##type; \ + add %g5, 0x20, %g5; \ + \ + /* For 4 trap levels with 4 registers, memory required is \ + 4*8*4 = 0x80 bytes */ + +/* Save all state into context at %g1 */ +#define SAVE_CPU_STATE(type) \ + SAVE_CPU_WINDOW_STATE(type); \ + SAVE_CPU_TRAP_STATE(type); + + +#define RESTORE_CPU_WINDOW_STATE(type) \ + /* Restore window state from context at %g1 */ \ + \ + /* Get the number of windows in %g6 */ \ + rdpr %ver, %g6; \ + and %g6, 0xf, %g6; \ + \ + mov %g6, %g4; \ + inc %g4; \ + \ + /* Set starting window */ \ + ldx [%g1], %g7; \ + \ + /* Now iterate through all of the windows restoring all l and i registers */ \ + add %g1, 0x90, %g5; \ + \ +restore_cpu_window_##type: \ + wrpr %g7, %cwp; \ + ldx [%g5], %l0; \ + ldx [%g5 + 0x8], %l1; \ + ldx [%g5 + 0x10], %l2; \ + ldx [%g5 + 0x18], %l3; \ + ldx [%g5 + 0x20], %l4; \ + ldx [%g5 + 0x28], %l5; \ + ldx [%g5 + 0x30], %l6; \ + ldx [%g5 + 0x38], %l7; \ + ldx [%g5 + 0x40], %i0; \ + ldx [%g5 + 0x48], %i1; \ + ldx [%g5 + 0x50], %i2; \ + ldx [%g5 + 0x58], %i3; \ + ldx [%g5 + 0x60], %i4; \ + ldx [%g5 + 0x68], %i5; \ + ldx [%g5 + 0x70], %i6; \ + ldx [%g5 + 0x78], %i7; \ + dec %g7; \ + and %g7, %g6, %g7; \ + subcc %g4, 1, %g4; \ + bne restore_cpu_window_##type; \ + add %g5, 0x80, %g5; \ + \ + /* Restore the window registers to their original value */ \ + ldx [%g1], %g7; \ + wrpr %g7, %cwp; \ + ldx [%g1 + 0x8], %g7; \ + wrpr %g7, %cansave; \ + ldx [%g1 + 0x10], %g7; \ + wrpr %g7, %canrestore; \ + ldx [%g1 + 0x18], %g7; \ + wrpr %g7, %otherwin; \ + ldx [%g1 + 0x20], %g7; \ + wrpr %g7, %wstate; \ + ldx [%g1 + 0x28], %g7; \ + wrpr %g7, %cleanwin; \ + \ + ldx [%g1 + 0x30], %o0; \ + ldx [%g1 + 0x38], %o1; \ + ldx [%g1 + 0x40], %o2; \ + ldx [%g1 + 0x48], %o3; \ + ldx [%g1 + 0x50], %o4; \ + ldx [%g1 + 0x58], %o5; \ + ldx [%g1 + 0x60], %o6; \ + ldx [%g1 + 0x68], %o7; \ + \ + ldx [%g1 + 0x70], %g7; \ + wrpr %g7, %pstate; \ + ldx [%g1 + 0x78], %g7; \ + wr %g7, 0, %y; \ + ldx [%g1 + 0x80], %g7; \ + wr %g7, 0, %fprs; \ + + +#define RESTORE_CPU_TRAP_STATE(type) \ + /* Restore trap state from context at %g1 */ \ + add %g1, 0x490, %g5; \ + mov 4, %g6; \ + \ +restore_trap_state_##type: \ + deccc %g6; \ + wrpr %g6, %tl; \ + ldx [%g5], %g7; \ + wrpr %g7, %tpc; \ + ldx [%g5 + 0x8], %g7; \ + wrpr %g7, %tnpc; \ + ldx [%g5 + 0x10], %g7; \ + wrpr %g7, %tstate; \ + ldx [%g5 + 0x18], %g7; \ + wrpr %g7, %tt; \ + bne restore_trap_state_##type; \ + add %g5, 0x20, %g5; \ + \ + ldx [%g1 + 0x88], %g7; \ + wrpr %g7, %tl + +/* Restore all state from context at %g1 */ +#define RESTORE_CPU_STATE(type) \ + RESTORE_CPU_WINDOW_STATE(type); \ + RESTORE_CPU_TRAP_STATE(type); diff --git a/roms/openbios/arch/sparc64/ldscript b/roms/openbios/arch/sparc64/ldscript index 54288e825..c5cc6a5ce 100644 --- a/roms/openbios/arch/sparc64/ldscript +++ b/roms/openbios/arch/sparc64/ldscript @@ -50,6 +50,11 @@ SECTIONS *(.bss.*) *(COMMON) + _fcstack = .; + . += 32768; + . = ALIGN(16); + _efcstack = .; + _stack = .; . += STACK_SIZE; . = ALIGN(16); diff --git a/roms/openbios/arch/sparc64/lib.c b/roms/openbios/arch/sparc64/lib.c index e9101af52..4709ca8fe 100644 --- a/roms/openbios/arch/sparc64/lib.c +++ b/roms/openbios/arch/sparc64/lib.c @@ -458,10 +458,10 @@ NODE_METHODS(mmu) = { void ob_mmu_init(const char *cpuname, uint64_t ram_size) { /* memory node */ - REGISTER_NODE_METHODS(memory, "/memory"); + REGISTER_NODE(memory); /* MMU node */ - REGISTER_NODE_METHODS(mmu, "/virtual-memory"); + REGISTER_NODE(mmu); ofmem_register(find_dev("/memory"), find_dev("/virtual-memory")); diff --git a/roms/openbios/arch/sparc64/vectors.S b/roms/openbios/arch/sparc64/vectors.S index 927c1cdc7..9d86b6bd8 100644 --- a/roms/openbios/arch/sparc64/vectors.S +++ b/roms/openbios/arch/sparc64/vectors.S @@ -24,6 +24,7 @@ */ #define __ASSEMBLY__ +#include "cpustate.h" #include "pstate.h" #include <asm/asi.h> #define ASI_BP ASI_PHYS_BYPASS_EC_E @@ -276,17 +277,8 @@ tl1_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8) .section ".data" .align 8 - .globl tlb_handler_stack_top, tlb_handler_stack_pointer, obp_ticks_pointer + .globl obp_ticks_pointer - ! Stack for the tlb MMU trap handlers -tlb_handler_stack_bottom: - .skip 8192 -tlb_handler_stack_top: - .skip 8 - - ! MMU trap handler stack pointer -tlb_handler_stack_pointer: - .xword tlb_handler_stack_top ! Pointer to current tick value obp_ticks_pointer: @@ -336,234 +328,30 @@ fill_32bit: restored retry -/* - * SAVE_CPU_STATE and RESTORE_CPU_STATE are macros used to enable a context switch - * to C to occur within the MMU I/D TLB miss handlers. - * - * Because these handlers are called on a TLB miss, we cannot use flushw to store - * processor window state on the stack, as the memory areas used by each window's - * stack pointer may not be in the TLB, causing recursive TLB miss traps. - * - * For this reason, we save window state by manually rotating the window registers - * and saving their contents (along with other vital registers) into a special - * tlb_handler_stack defined above which is guaranteed to be locked in the TLB, and - * so won't cause issues with trap recursion. - * - * Once this process is complete, we remain in a TL=0, CWP=0 state (with IE=1 to allow - * window fill/spill traps if required), switch to our safe tlb_handler_stack and - * invoke the miss handler. - */ - -#define SAVE_CPU_STATE(type) \ - /* Set up our exception stack pointer in %g1 */ \ - setx tlb_handler_stack_pointer, %g7, %g6; \ - ldx [%g6], %g1; \ - add %g1, -0x510, %g1; \ - \ - /* First save the various state registers */ \ - rdpr %cwp, %g7; \ - stx %g7, [%g1]; \ - rdpr %cansave, %g7; \ - stx %g7, [%g1 + 0x8]; \ - rdpr %canrestore, %g7; \ - stx %g7, [%g1 + 0x10]; \ - rdpr %otherwin, %g7; \ - stx %g7, [%g1 + 0x18]; \ - rdpr %wstate, %g7; \ - stx %g7, [%g1 + 0x20]; \ - rdpr %cleanwin, %g7; \ - stx %g7, [%g1 + 0x28]; \ - rdpr %pstate, %g7; \ - stx %g7, [%g1 + 0x30]; \ - \ - rd %y, %g7; \ - stx %g7, [%g1 + 0x38]; \ - rd %fprs, %g7; \ - stx %g7, [%g1 + 0x40]; \ - \ - rdpr %tl, %g7; \ - stx %g7, [%g1 + 0x48]; \ - \ - /* Trap state */ \ - add %g1, 0x50, %g5; \ - mov 4, %g6; \ - \ -save_trap_state_##type: \ - deccc %g6; \ - wrpr %g6, %tl; \ - rdpr %tpc, %g7; \ - stx %g7, [%g5]; \ - rdpr %tnpc, %g7; \ - stx %g7, [%g5 + 0x8]; \ - rdpr %tstate, %g7; \ - stx %g7, [%g5 + 0x10]; \ - rdpr %tt, %g7; \ - stx %g7, [%g5 + 0x18]; \ - bne save_trap_state_##type; \ - add %g5, 0x20, %g5; \ - \ - /* For 4 trap levels with 4 registers, memory required is - 4*8*4 = 0x80 bytes */ \ - \ - /* Save the o registers */ \ - stx %o0, [%g1 + 0xd0]; \ - stx %o1, [%g1 + 0xd8]; \ - stx %o2, [%g1 + 0xe0]; \ - stx %o3, [%g1 + 0xe8]; \ - stx %o4, [%g1 + 0xf0]; \ - stx %o5, [%g1 + 0xf8]; \ - stx %o6, [%g1 + 0x100]; \ - stx %o7, [%g1 + 0x108]; \ - \ - /* Now iterate through all of the windows saving all l and i registers */ \ - add %g1, 0x110, %g5; \ - \ - /* Get the number of windows in %g6 */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - inc %g6; \ - \ -save_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ - stx %l0, [%g5]; \ - stx %l1, [%g5 + 0x8]; \ - stx %l2, [%g5 + 0x10]; \ - stx %l3, [%g5 + 0x18]; \ - stx %l4, [%g5 + 0x20]; \ - stx %l5, [%g5 + 0x28]; \ - stx %l6, [%g5 + 0x30]; \ - stx %l7, [%g5 + 0x38]; \ - stx %i0, [%g5 + 0x40]; \ - stx %i1, [%g5 + 0x48]; \ - stx %i2, [%g5 + 0x50]; \ - stx %i3, [%g5 + 0x58]; \ - stx %i4, [%g5 + 0x60]; \ - stx %i5, [%g5 + 0x68]; \ - stx %i6, [%g5 + 0x70]; \ - stx %i7, [%g5 + 0x78]; \ - bne save_cpu_window_##type; \ - add %g5, 0x80, %g5; \ - \ - /* For 8 windows with 16 registers to save in the window, memory required - is 16*8*8 = 0x400 bytes */ \ - \ - /* Now we should be in window 0 so update the other window registers */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - dec %g6; \ - wrpr %g6, %cansave; \ - \ - wrpr %g0, %cleanwin; \ - wrpr %g0, %canrestore; \ - wrpr %g0, %otherwin; \ - \ - /* Update our exception stack pointer */ \ - setx tlb_handler_stack_pointer, %g7, %g6; \ - stx %g1, [%g6]; - - -#define RESTORE_CPU_STATE(type) \ - /* Set up our exception stack pointer in %g1 */ \ - setx tlb_handler_stack_pointer, %g7, %g6; \ - ldx [%g6], %g1; \ - \ - /* Get the number of windows in %g6 */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - inc %g6; \ - \ - /* Now iterate through all of the windows restoring all l and i registers */ \ - add %g1, 0x110, %g5; \ - \ -restore_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ - ldx [%g5], %l0; \ - ldx [%g5 + 0x8], %l1; \ - ldx [%g5 + 0x10], %l2; \ - ldx [%g5 + 0x18], %l3; \ - ldx [%g5 + 0x20], %l4; \ - ldx [%g5 + 0x28], %l5; \ - ldx [%g5 + 0x30], %l6; \ - ldx [%g5 + 0x38], %l7; \ - ldx [%g5 + 0x40], %i0; \ - ldx [%g5 + 0x48], %i1; \ - ldx [%g5 + 0x50], %i2; \ - ldx [%g5 + 0x58], %i3; \ - ldx [%g5 + 0x60], %i4; \ - ldx [%g5 + 0x68], %i5; \ - ldx [%g5 + 0x70], %i6; \ - ldx [%g5 + 0x78], %i7; \ - bne restore_cpu_window_##type; \ - add %g5, 0x80, %g5; \ - \ - /* Restore the window registers to their original value */ \ - ldx [%g1], %g7; \ - wrpr %g7, %cwp; \ - ldx [%g1 + 0x8], %g7; \ - wrpr %g7, %cansave; \ - ldx [%g1 + 0x10], %g7; \ - wrpr %g7, %canrestore; \ - ldx [%g1 + 0x18], %g7; \ - wrpr %g7, %otherwin; \ - ldx [%g1 + 0x20], %g7; \ - wrpr %g7, %wstate; \ - ldx [%g1 + 0x28], %g7; \ - wrpr %g7, %cleanwin; \ - ldx [%g1 + 0x30], %g7; \ - wrpr %g7, %pstate; \ - \ - /* Restore the o registers */ \ - ldx [%g1 + 0xd0], %o0; \ - ldx [%g1 + 0xd8], %o1; \ - ldx [%g1 + 0xe0], %o2; \ - ldx [%g1 + 0xe8], %o3; \ - ldx [%g1 + 0xf0], %o4; \ - ldx [%g1 + 0xf8], %o5; \ - ldx [%g1 + 0x100], %o6; \ - ldx [%g1 + 0x108], %o7; \ - \ - /* Restore the trap state */ \ - add %g1, 0x50, %g5; \ - mov 4, %g6; \ - \ -restore_trap_state_##type: \ - deccc %g6; \ - wrpr %g6, %tl; \ - ldx [%g5], %g7; \ - wrpr %g7, %tpc; \ - ldx [%g5 + 0x8], %g7; \ - wrpr %g7, %tnpc; \ - ldx [%g5 + 0x10], %g7; \ - wrpr %g7, %tstate; \ - ldx [%g5 + 0x18], %g7; \ - wrpr %g7, %tt; \ - bne restore_trap_state_##type; \ - add %g5, 0x20, %g5; \ - \ - ldx [%g1 + 0x38], %g7; \ - wr %g7, 0, %y; \ - ldx [%g1 + 0x40], %g7; \ - wr %g7, 0, %fprs; \ - ldx [%g1 + 0x48], %g7; \ - wrpr %g7, %tl; \ - \ - /* Restore exception stack pointer to previous value */ \ - setx tlb_handler_stack_pointer, %g7, %g6; \ - add %g1, 0x510, %g1; \ - stx %g1, [%g6]; - .globl reload_DMMU_tlb, reload_IMMU_tlb, bug reload_DMMU_tlb: - + + /* Save CPU state to stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, -CONTEXT_STATE_SIZE, %g1 + stx %g1, [%g7] + SAVE_CPU_STATE(dtlb) - /* Switch to TLB locked stack space (note we add an additional 192 bytes required for + /* Switch to 8K TLB locked OpenBIOS stack (note we add an additional 192 bytes required for gcc to save its arguments when building with -O0) */ - add %g1, -STACK_BIAS - 192, %sp + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g6 + setx CONTEXT_STACK_SIZE, %g4, %g5 + sub %g6, %g5, %g6 + stx %g6, [%g7] + + setx - 2047 - 192, %g6, %g7 + add %g1, %g7, %g7 + mov %g7, %sp /* Enable interrupts for window spill/fill traps */ rdpr %pstate, %g7 @@ -577,18 +365,44 @@ reload_DMMU_tlb: rdpr %pstate, %g7 andn %g7, PSTATE_IE, %g7 wrpr %g7, %pstate - + + /* Restore CPU state from stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + setx CONTEXT_STACK_SIZE, %g4, %g5 + add %g1, %g5, %g1 + stx %g1, [%g7] + RESTORE_CPU_STATE(dtlb) - + + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, CONTEXT_STATE_SIZE, %g1 + stx %g1, [%g7] + retry reload_IMMU_tlb: - + + /* Save CPU state to stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, -CONTEXT_STATE_SIZE, %g1 + stx %g1, [%g7] + SAVE_CPU_STATE(itlb) - /* Switch to TLB locked stack space (note we add an additional 192 bytes required for + /* Switch to 8K TLB locked OpenBIOS stack (note we add an additional 192 bytes required for gcc to save its arguments when building with -O0) */ - add %g1, -STACK_BIAS - 192, %sp + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g6 + setx CONTEXT_STACK_SIZE, %g4, %g5 + sub %g6, %g5, %g6 + stx %g6, [%g7] + + setx - 2047 - 192, %g6, %g7 + add %g1, %g7, %g7 + mov %g7, %sp /* Enable interrupts for window spill/fill traps */ rdpr %pstate, %g7 @@ -602,8 +416,20 @@ reload_IMMU_tlb: rdpr %pstate, %g7 andn %g7, PSTATE_IE, %g7 wrpr %g7, %pstate - + + /* Restore CPU state from stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + setx CONTEXT_STACK_SIZE, %g4, %g5 + add %g1, %g5, %g1 + stx %g1, [%g7] + RESTORE_CPU_STATE(itlb) + + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, CONTEXT_STATE_SIZE, %g1 + stx %g1, [%g7] retry diff --git a/roms/openbios/config/scripts/switch-arch b/roms/openbios/config/scripts/switch-arch index 7b8b457f6..ab3b4ce69 100755 --- a/roms/openbios/config/scripts/switch-arch +++ b/roms/openbios/config/scripts/switch-arch @@ -17,48 +17,57 @@ if [ x"$1" = x -o "$1" = "-help" ]; then exit 0 fi -crosscflags() +is_bigendian() { - host=$1 - target=$2 - - if test "$host" = "powerpc" -o "$host" = "ppc" \ - -o "$host" = "mips" -o "$host" = "s390" \ - -o "$host" = "sparc32" -o "$host" = "sparc64" \ - -o "$host" = "m68k" -o "$host" = "armv4b"; then - hostbigendian="yes" + cpu=$1 + + if test "$cpu" = "powerpc" -o "$cpu" = "ppc" \ + -o "$cpu" = "powerpc64" -o "$cpu" = "ppc64" \ + -o "$cpu" = "mips" -o "$cpu" = "s390" \ + -o "$cpu" = "sparc32" -o "$cpu" = "sparc64" \ + -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then + echo yes else - hostbigendian="no" + echo no fi +} -# host long bits test - if test "$host" = "sparc64" -o "$host" = "ia64" \ - -o "$host" = "amd64" -o "$host" = "x86_64" \ - -o "$host" = "alpha"; then - hostlongbits="64" +longbits() +{ + cpu=$1 + if test "$cpu" = "sparc64" -o "$cpu" = "ia64" \ + -o "$cpu" = "amd64" -o "$cpu" = "x86_64" \ + -o "$cpu" = "powerpc64" -o "$cpu" = "ppc64" \ + -o "$cpu" = "alpha"; then + echo 64 else - hostlongbits="32" + echo 32 fi +} - if test "$target" = "powerpc" -o "$target" = "ppc" \ - -o "$target" = "powerpc64" -o "$target" = "ppc64" \ - -o "$target" = "mips" -o "$target" = "s390" \ - -o "$target" = "sparc32" -o "$target" = "sparc64" \ - -o "$target" = "m68k" -o "$target" = "armv4b"; then - targetbigendian="yes" - else - targetbigendian="no" - fi +basearch() +{ + arch=$1 + case $arch in + powerpc|ppc64|powerpc64) + echo ppc + ;; + *) + echo $arch + ;; + esac +} -# target long bits test - if test "$target" = "sparc64" -o "$target" = "ia64" \ - -o "$target" = "amd64" -o "$target" = "x86_64" \ - -o "$target" = "powerpc64" -o "$target" = "ppc64" \ - -o "$target" = "alpha"; then - targetlongbits="64" - else - targetlongbits="32" - fi +crosscflags() +{ + host=$1 + target=$2 + + hostbigendian=$(is_bigendian $host) + hostlongbits=$(longbits $host) + + targetbigendian=$(is_bigendian $target) + targetlongbits=$(longbits $target) if test "$targetbigendian" = "$hostbigendian"; then cflags="-USWAP_ENDIANNESS" @@ -99,6 +108,7 @@ archname() select_prefix() { + BASEARCH=$(basearch $ARCH) for target_arch ; do TARGETS="${target_arch}-unknown-linux-gnu- ${target_arch}-linux-gnu- ${target_arch}-linux- ${target_arch}-elf- ${target_arch}-eabi-" @@ -113,7 +123,8 @@ select_prefix() return fi done - if [ "$ARCH" = "$HOSTARCH" ]; then + if [ "$BASEARCH" = "$(basearch $HOSTARCH)" ]; then + TARGET="" return fi done @@ -244,7 +255,6 @@ for ARCH in $arch_list; do esac done - BASEARCH=$ARCH case $ARCH in amd64) select_prefix x86_64 @@ -255,7 +265,8 @@ for ARCH in $arch_list; do ppc) select_prefix powerpc powerpc64 if [ "$unix" = "no" ]; then - CFLAGS="-m32 -msoft-float -fno-builtin-bcopy -fno-builtin-log2" + # 604 cpu includes support for PReP as well as Mac + CFLAGS="-m32 -mcpu=604 -msoft-float -fno-builtin-bcopy -fno-builtin-log2" AS_FLAGS="-m32" else CFLAGS="-fno-builtin" @@ -265,13 +276,14 @@ for ARCH in $arch_list; do ppc64) select_prefix powerpc64 - CFLAGS="-Wa,-a64 -m64 -msoft-float -fno-builtin" + + # 970 cpu is used in all 64-bit Macs but disable altivec + CFLAGS="-mcpu=970 -mno-altivec -Wa,-a64 -m64 -msoft-float -fno-builtin" AS_FLAGS="-Wa,-a64" - BASEARCH=ppc ;; sparc32) - select_prefix sparc + select_prefix sparc sparc64 CFLAGS="-Wa,-xarch=v8 -Wa,-32 -m32 -mcpu=supersparc -fno-builtin" AS_FLAGS="-Wa,-xarch=v8 -Wa,-32" ;; diff --git a/roms/openbios/drivers/escc.c b/roms/openbios/drivers/escc.c index afb97fa8a..1990e798d 100644 --- a/roms/openbios/drivers/escc.c +++ b/roms/openbios/drivers/escc.c @@ -386,15 +386,37 @@ escc_add_channel(const char *path, const char *node, phys_addr_t addr, phandle_t dnode, aliases; cell props[10]; - int offset; + ucell offset; + int index; int legacy; - + + int dbdma_offsets[2][2] = { + /* ch-b */ + { 0x6, 0x7 }, + /* ch-a */ + { 0x4, 0x5 } + }; + + int reg_offsets[2][2][3] = { + { + /* ch-b */ + { 0x00, 0x10, 0x40 }, + /* ch-a */ + { 0x20, 0x30, 0x50 } + },{ + /* legacy ch-b */ + { 0x0, 0x2, 0x8 }, + /* legacy ch-a */ + { 0x4, 0x6, 0xa } + } + }; + switch (esnum) { - case 2: offset = 1; legacy = 0; break; - case 3: offset = 0; legacy = 0; break; - case 4: offset = 1; legacy = 1; break; - case 5: offset = 0; legacy = 1; break; - default: return; + case 2: index = 1; legacy = 0; break; + case 3: index = 0; legacy = 0; break; + case 4: index = 1; legacy = 1; break; + case 5: index = 0; legacy = 1; break; + default: return; } /* add device */ @@ -425,48 +447,46 @@ escc_add_channel(const char *path, const char *node, phys_addr_t addr, set_property(dnode, "compatible", buf, 9); if (legacy) { - props[0] = IO_ESCC_LEGACY_OFFSET + offset * 0x4; - props[1] = 0x00000001; - props[2] = IO_ESCC_LEGACY_OFFSET + offset * 0x4 + 2; - props[3] = 0x00000001; - props[4] = IO_ESCC_LEGACY_OFFSET + offset * 0x4 + 6; - props[5] = 0x00000001; - set_property(dnode, "reg", (char *)&props, 6 * sizeof(cell)); + offset = IO_ESCC_LEGACY_OFFSET; } else { - props[0] = IO_ESCC_OFFSET + offset * 0x20; - props[1] = 0x00000020; - set_property(dnode, "reg", (char *)&props, 2 * sizeof(cell)); + offset = IO_ESCC_OFFSET; } - if (legacy) { - props[0] = addr + IO_ESCC_LEGACY_OFFSET + offset * 0x4; - } else { - props[0] = addr + IO_ESCC_OFFSET + offset * 0x20; - } + props[0] = offset + reg_offsets[legacy][index][0]; + props[1] = 0x1; + props[2] = offset + reg_offsets[legacy][index][1]; + props[3] = 0x1; + props[4] = offset + reg_offsets[legacy][index][2]; + props[5] = 0x1; + props[6] = 0x8000 + dbdma_offsets[index][0] * 0x100; + props[7] = 0x100; + props[8] = 0x8000 + dbdma_offsets[index][1] * 0x100; + props[9] = 0x100; + set_property(dnode, "reg", (char *)&props, 10 * sizeof(cell)); + + props[0] = addr + offset + reg_offsets[legacy][index][0]; OLDWORLD(set_property(dnode, "AAPL,address", (char *)&props, 1 * sizeof(cell))); - props[0] = 0x00000010 - offset; + props[0] = 0x10 - index; OLDWORLD(set_property(dnode, "AAPL,interrupts", (char *)&props, 1 * sizeof(cell))); - props[0] = (0x24) + offset; - props[1] = 0; - props[2] = 0; + props[0] = (0x24) + index; + props[1] = 0x1; + props[2] = dbdma_offsets[index][0]; + props[3] = 0x0; + props[4] = dbdma_offsets[index][1]; + props[5] = 0x0; NEWWORLD(set_property(dnode, "interrupts", - (char *)&props, 3 * sizeof(cell))); + (char *)&props, 6 * sizeof(cell))); + + set_int_property(dnode, "slot-names", 0); device_end(); - if (legacy) { - uart_init_line( - (unsigned char*)addr + IO_ESCC_LEGACY_OFFSET + offset * 0x4, - CONFIG_SERIAL_SPEED); - } else { - uart_init_line( - (unsigned char*)addr + IO_ESCC_OFFSET + offset * 0x20, - CONFIG_SERIAL_SPEED); - } + uart_init_line((unsigned char*)addr + offset + reg_offsets[legacy][index][0], + CONFIG_SERIAL_SPEED); } void @@ -494,6 +514,7 @@ escc_init(const char *path, phys_addr_t addr) set_property(dnode, "device_type", "escc", strlen("escc") + 1); set_property(dnode, "compatible", "escc\0CHRP,es0", 14); + set_property(dnode, "ranges", "", 0); fword("finish-device"); @@ -521,6 +542,7 @@ escc_init(const char *path, phys_addr_t addr) set_property(dnode, "device_type", "escc-legacy", strlen("escc-legacy") + 1); set_property(dnode, "compatible", "chrp,es1", 9); + set_property(dnode, "ranges", "", 0); fword("finish-device"); diff --git a/roms/openbios/drivers/ide.c b/roms/openbios/drivers/ide.c index 5125b78b9..1da60c895 100644 --- a/roms/openbios/drivers/ide.c +++ b/roms/openbios/drivers/ide.c @@ -73,13 +73,13 @@ static inline void ide_add_channel(struct ide_channel *chan) channels = chan; } -static struct ide_channel *ide_seek_channel(const char *name) +static struct ide_channel *ide_seek_channel(phandle_t ph) { struct ide_channel *current; current = channels; while (current) { - if (!strcmp(current->name, name)) + if (current->ph == ph) return current; current = current->next; } @@ -1247,11 +1247,10 @@ ob_ide_initialize(int *idx) static void ob_ide_open(int *idx) { - int ret=1, len; + int ret=1; phandle_t ph; struct ide_drive *drive; struct ide_channel *chan; - char *idename; int unit; fword("my-unit"); @@ -1260,9 +1259,8 @@ ob_ide_open(int *idx) fword("my-parent"); fword("ihandle>phandle"); ph=(phandle_t)POP(); - idename=get_property(ph, "name", &len); - chan = ide_seek_channel(idename); + chan = ide_seek_channel(ph); drive = &chan->drives[unit]; *(struct ide_drive **)idx = drive; @@ -1380,9 +1378,6 @@ int ob_ide_init(const char *path, uint32_t io_port0, uint32_t ctl_port0, chan = malloc(sizeof(struct ide_channel)); - snprintf(chan->name, sizeof(chan->name), - DEV_NAME, current_channel); - chan->mmio = 0; for (j = 0; j < 8; j++) @@ -1424,9 +1419,9 @@ int ob_ide_init(const char *path, uint32_t io_port0, uint32_t ctl_port0, snprintf(nodebuff, sizeof(nodebuff), "%s/" DEV_NAME, path, current_channel); - REGISTER_NAMED_NODE(ob_ide_ctrl, nodebuff); + REGISTER_NAMED_NODE_PHANDLE(ob_ide_ctrl, nodebuff, dnode); - dnode = find_dev(nodebuff); + chan->ph = dnode; #if !defined(CONFIG_PPC) && !defined(CONFIG_SPARC64) props[0]=14; props[1]=0; @@ -1468,11 +1463,9 @@ int ob_ide_init(const char *path, uint32_t io_port0, uint32_t ctl_port0, break; } IDE_DPRINTF("%s]: %s\n", media, drive->model); - snprintf(nodebuff, sizeof(nodebuff), - "%s/" DEV_NAME "/%s", path, current_channel, - media); - REGISTER_NAMED_NODE(ob_ide, nodebuff); - dnode=find_dev(nodebuff); + snprintf(nodebuff, sizeof(nodebuff), "%s/%s", + get_path_from_ph(dnode), media); + REGISTER_NAMED_NODE_PHANDLE(ob_ide, nodebuff, dnode); set_int_property(dnode, "reg", j); /* create aliases */ @@ -1549,16 +1542,13 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels) struct ide_channel *chan; /* IDE ports on Macs are numbered from 3. - * Also see comments in macio.c:openpic_init() */ + * Also see comments in pci.c:ob_pci_host_set_interrupt_map() */ current_channel = 3; - for (i = 0; i < nb_channels; i++, current_channel++) { + for (i = 0; i < nb_channels; i++) { chan = malloc(sizeof(struct ide_channel)); - snprintf(chan->name, sizeof(chan->name), - DEV_NAME, current_channel); - chan->mmio = addr + MACIO_IDE_OFFSET + i * MACIO_IDE_SIZE; chan->obide_inb = macio_ide_inb; @@ -1596,9 +1586,9 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels) snprintf(nodebuff, sizeof(nodebuff), "%s/" DEV_NAME, path, current_channel); - REGISTER_NAMED_NODE(ob_ide_ctrl, nodebuff); + REGISTER_NAMED_NODE_PHANDLE(ob_ide_ctrl, nodebuff, dnode); - dnode = find_dev(nodebuff); + chan->ph = dnode; set_property(dnode, "compatible", (is_oldworld() ? "heathrow-ata" : "keylargo-ata"), 13); @@ -1661,7 +1651,7 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels) OLDWORLD(set_property(dnode, "AAPL,address", (char *)&props, 2*sizeof(props[0]))); - props[0] = 0; + props[0] = i; set_property(dnode, "AAPL,bus-id", (char*)props, 1 * sizeof(props[0])); IDE_DPRINTF(DEV_NAME": [io ports 0x%lx]\n", @@ -1691,11 +1681,9 @@ int macio_ide_init(const char *path, uint32_t addr, int nb_channels) break; } IDE_DPRINTF("%s]: %s\n", media, drive->model); - snprintf(nodebuff, sizeof(nodebuff), - "%s/" DEV_NAME "/%s", path, current_channel, - media); - REGISTER_NAMED_NODE(ob_ide, nodebuff); - dnode = find_dev(nodebuff); + snprintf(nodebuff, sizeof(nodebuff), "%s/%s", + get_path_from_ph(dnode), media); + REGISTER_NAMED_NODE_PHANDLE(ob_ide, nodebuff, dnode); set_int_property(dnode, "reg", j); /* create aliases */ diff --git a/roms/openbios/drivers/ide.h b/roms/openbios/drivers/ide.h index d6c4b9f5d..8983c8ecf 100644 --- a/roms/openbios/drivers/ide.h +++ b/roms/openbios/drivers/ide.h @@ -167,7 +167,7 @@ struct ide_drive { struct ide_channel { - char name[32]; + phandle_t ph; struct ide_channel *next; /* diff --git a/roms/openbios/drivers/obio.c b/roms/openbios/drivers/obio.c index 7c135a362..4ac063188 100644 --- a/roms/openbios/drivers/obio.c +++ b/roms/openbios/drivers/obio.c @@ -26,8 +26,6 @@ #define PROMDEV_SCREEN 0 /* output to screen */ #define PROMDEV_TTYA 1 /* in/out to ttya */ -/* DECLARE data structures for the nodes. */ -DECLARE_UNNAMED_NODE( ob_obio, INSTALL_OPEN, sizeof(int) ); void ob_new_obio_device(const char *name, const char *type) @@ -397,45 +395,6 @@ ob_smp_init(unsigned long mem_size) } static void -ob_obio_open(__attribute__((unused))int *idx) -{ - int ret=1; - RET ( -ret ); -} - -static void -ob_obio_close(__attribute__((unused))int *idx) -{ - selfword("close-deblocker"); -} - -static void -ob_obio_initialize(__attribute__((unused))int *idx) -{ - push_str("/"); - fword("find-device"); - fword("new-device"); - - push_str("obio"); - fword("device-name"); - - push_str("hierarchical"); - fword("device-type"); - - PUSH(2); - fword("encode-int"); - push_str("#address-cells"); - fword("property"); - - PUSH(1); - fword("encode-int"); - push_str("#size-cells"); - fword("property"); - - fword("finish-device"); -} - -static void ob_set_obio_ranges(uint64_t base) { push_str("/obio"); @@ -458,27 +417,6 @@ ob_set_obio_ranges(uint64_t base) fword("property"); } -static void -ob_obio_decodeunit(__attribute__((unused)) int *idx) -{ - fword("decode-unit-sbus"); -} - - -static void -ob_obio_encodeunit(__attribute__((unused)) int *idx) -{ - fword("encode-unit-sbus"); -} - -NODE_METHODS(ob_obio) = { - { NULL, ob_obio_initialize }, - { "open", ob_obio_open }, - { "close", ob_obio_close }, - { "encode-unit", ob_obio_encodeunit }, - { "decode-unit", ob_obio_decodeunit }, -}; - int ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, @@ -491,10 +429,6 @@ ob_obio_init(uint64_t slavio_base, unsigned long fd_offset, // http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt //printk("Initializing OBIO devices...\n"); -#if 0 // XXX - REGISTER_NAMED_NODE(ob_obio, "/obio"); - device_end(); -#endif ob_set_obio_ranges(slavio_base); // Zilog Z8530 serial ports, see http://www.zilog.com diff --git a/roms/openbios/drivers/pci.c b/roms/openbios/drivers/pci.c index 935ecb8f8..5062f302f 100644 --- a/roms/openbios/drivers/pci.c +++ b/roms/openbios/drivers/pci.c @@ -144,9 +144,16 @@ static void dump_reg_property(const char* description, int nreg, u32 *reg) } #endif -static unsigned long pci_bus_addr_to_host_addr(uint32_t ba) +static unsigned long pci_bus_addr_to_host_addr(int space, uint32_t ba) { - return arch->host_pci_base + (unsigned long)ba; + if (space == IO_SPACE) { + return arch->io_base + (unsigned long)ba; + } else if (space == MEMORY_SPACE_32) { + return arch->host_pci_base + (unsigned long)ba; + } else { + /* Return unaltered to aid debugging property values */ + return (unsigned long)ba; + } } static void @@ -340,22 +347,27 @@ ob_pci_encode_unit(int *idx) ss, dev, fn, buf); } -/* ( pci-addr.lo pci-addr.hi size -- virt ) */ +/* ( pci-addr.lo pci-addr.mid pci-addr.hi size -- virt ) */ static void ob_pci_map_in(int *idx) { phys_addr_t phys; uint32_t ba; - ucell size, virt; + ucell size, virt, tmp; + int space; PCI_DPRINTF("ob_pci_bar_map_in idx=%p\n", idx); size = POP(); + tmp = POP(); POP(); ba = POP(); - phys = pci_bus_addr_to_host_addr(ba); + /* Get the space from the pci-addr.hi */ + space = ((tmp & PCI_RANGE_TYPE_MASK) >> 24); + + phys = pci_bus_addr_to_host_addr(space, ba); #if defined(CONFIG_OFMEM) ofmem_claim_phys(phys, size, 0); @@ -448,13 +460,18 @@ static void pci_host_set_ranges(const pci_config_t *config) int ncells; ncells = 0; - /* first encode PCI configuration space */ - { - ncells += pci_encode_phys_addr(props + ncells, 0, CONFIGURATION_SPACE, + +#ifdef CONFIG_SPARC64 + /* While configuration space isn't mentioned in the IEEE-1275 PCI + bindings, it appears in the PCI host bridge ranges property in + real device trees. Hence we disable this range for all host + bridges except for SPARC, particularly as it causes Darwin/OS X + to incorrectly calculated PCI memory space ranges on PPC. */ + ncells += pci_encode_phys_addr(props + ncells, 0, CONFIGURATION_SPACE, config->dev, 0, 0); ncells += host_encode_phys_addr(props + ncells, arch->cfg_addr); ncells += pci_encode_size(props + ncells, arch->cfg_len); - } +#endif if (arch->io_base) { ncells += pci_encode_phys_addr(props + ncells, 0, IO_SPACE, @@ -585,13 +602,18 @@ static void pci_set_AAPL_address(const pci_config_t *config) { phandle_t dev = get_cur_dev(); cell props[7]; - int ncells, i; + uint32_t mask; + int ncells, i, flags, space_code; ncells = 0; for (i = 0; i < 6; i++) { if (!config->assigned[i] || !config->sizes[i]) continue; - props[ncells++] = config->assigned[i] & ~0x0000000F; + pci_decode_pci_addr(config->assigned[i], + &flags, &space_code, &mask); + + props[ncells++] = pci_bus_addr_to_host_addr(space_code, + config->assigned[i] & ~mask); } if (ncells) set_property(dev, "AAPL,address", (char *)props, @@ -752,13 +774,19 @@ int macio_keylargo_config_cb (const pci_config_t *config) int vga_config_cb (const pci_config_t *config) { unsigned long rom; - uint32_t rom_size, size; + uint32_t rom_size, size, mask; + int flags, space_code; phandle_t ph; if (config->assigned[0] != 0x00000000) { setup_video(); - rom = pci_bus_addr_to_host_addr(config->assigned[1] & ~0x0000000F); + pci_decode_pci_addr(config->assigned[1], + &flags, &space_code, &mask); + + rom = pci_bus_addr_to_host_addr(space_code, + config->assigned[1] & ~0x0000000F); + rom_size = config->sizes[1]; ph = get_cur_dev(); @@ -997,7 +1025,10 @@ static void ob_pci_add_properties(phandle_t phandle, } pci_set_assigned_addresses(phandle, config, num_bars); - OLDWORLD(pci_set_AAPL_address(config)); + + if (is_apple()) { + pci_set_AAPL_address(config); + } PCI_DPRINTF("\n"); } @@ -1397,9 +1428,11 @@ static void ob_pci_set_available(phandle_t host, unsigned long mem_base, unsigne static void ob_pci_host_set_interrupt_map(phandle_t host) { - phandle_t dnode = 0; - u32 props[128]; - int i; + phandle_t dnode = 0, pci_childnode = 0; + u32 props[128], intno; + int i, ncells, len; + u32 *val, addr; + char *reg; #if defined(CONFIG_PPC) phandle_t target_node; @@ -1430,12 +1463,12 @@ static void ob_pci_host_set_interrupt_map(phandle_t host) /* On a new world Mac these are not numbered but named by the * ATA version they support. Thus we have: ata-3, ata-3, ata-4 * On g3beige they all called just ide. - * We take ata-3 and ata-4 which seems to work for both - * at least for clients we care about */ - target_node = find_dev("/pci/mac-io/ata-3"); + * We take 2 x ata-3 buses which seems to work for + * at least the clients we care about */ + target_node = find_dev("/pci/mac-io/ata-3@20000"); set_int_property(target_node, "interrupt-parent", dnode); - target_node = find_dev("/pci/mac-io/ata-4"); + target_node = find_dev("/pci/mac-io/ata-3@21000"); set_int_property(target_node, "interrupt-parent", dnode); target_node = find_dev("/pci/mac-io/via-cuda"); @@ -1443,69 +1476,61 @@ static void ob_pci_host_set_interrupt_map(phandle_t host) target_node = find_dev("/pci"); set_int_property(target_node, "interrupt-parent", dnode); - - /* openpic interrupt mapping */ - for (i = 0; i < (7*8); i += 7) { - props[i + PCI_INT_MAP_PCI0] = 0; - props[i + PCI_INT_MAP_PCI1] = 0; - props[i + PCI_INT_MAP_PCI2] = 0; - props[i + PCI_INT_MAP_PCI_INT] = (i / 7) + 1; // starts at PINA=1 - props[i + PCI_INT_MAP_PIC_HANDLE] = dnode; - props[i + PCI_INT_MAP_PIC_INT] = arch->irqs[i / 7]; - props[i + PCI_INT_MAP_PIC_POL] = 3; - } - set_property(host, "interrupt-map", (char *)props, 7 * 8 * sizeof(props[0])); - - props[PCI_INT_MAP_PCI0] = 0; - props[PCI_INT_MAP_PCI1] = 0; - props[PCI_INT_MAP_PCI2] = 0; - props[PCI_INT_MAP_PCI_INT] = 0x7; - - set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); } -#elif defined(CONFIG_SPARC64) - int ncells, len; - u32 *val, addr; - char *reg; +#else + /* PCI host bridge is the default interrupt controller */ + dnode = host; +#endif /* Set interrupt-map for PCI devices with an interrupt pin present */ ncells = 0; PUSH(host); fword("child"); - dnode = POP(); - while (dnode) { - if (get_int_property(dnode, "interrupts", &len)) { - reg = get_property(dnode, "reg", &len); - if (reg) { + pci_childnode = POP(); + while (pci_childnode) { + intno = get_int_property(pci_childnode, "interrupts", &len); + if (len && intno) { + reg = get_property(pci_childnode, "reg", &len); + if (len && reg) { val = (u32 *)reg; for (i = 0; i < (len / sizeof(u32)); i += 5) { addr = val[i]; /* Device address is in 1st 32-bit word of encoded PCI address for config space */ - if (!(addr & 0x03000000)) { + if ((addr & PCI_RANGE_TYPE_MASK) == PCI_RANGE_CONFIG) { +#if defined(CONFIG_SPARC64) + ncells += pci_encode_phys_addr(props + ncells, 0, 0, addr, 0, 0); + props[ncells++] = intno; + props[ncells++] = dnode; + props[ncells++] = SUN4U_INTERRUPT(addr, intno); +#elif defined(CONFIG_PPC) ncells += pci_encode_phys_addr(props + ncells, 0, 0, addr, 0, 0); - props[ncells++] = 1; /* always interrupt pin 1 for QEMU */ - props[ncells++] = host; - props[ncells++] = SUN4U_INTERRUPT(addr, 1); + props[ncells++] = intno; + props[ncells++] = dnode; + props[ncells++] = arch->irqs[intno - 1]; + props[ncells++] = 3; +#else + /* Keep compiler quiet */ + dnode = dnode; +#endif } } } } - PUSH(dnode); + PUSH(pci_childnode); fword("peer"); - dnode = POP(); + pci_childnode = POP(); } set_property(host, "interrupt-map", (char *)props, ncells * sizeof(props[0])); props[0] = 0x0000f800; props[1] = 0x0; props[2] = 0x0; - props[3] = 7; + props[3] = 0x7; set_property(host, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0])); -#endif } int ob_pci_init(void) diff --git a/roms/openbios/drivers/pci.fs b/roms/openbios/drivers/pci.fs index 563b652a4..a7b56e1f8 100644 --- a/roms/openbios/drivers/pci.fs +++ b/roms/openbios/drivers/pci.fs @@ -12,59 +12,19 @@ rot encode-int encode+ ; -\ Get region offset for BAR reg -: pci-bar-offset@ ( bar-reg -- off.lo off.hi -1 | 0 ) - " reg" active-package get-package-property 0= if - begin - decode-phys \ ( reg prop prop-len phys.lo phys.mid phys.hi ) - ff and 5 pick = if - >r >r 3drop r> r> - -1 exit - else - 2drop - then - \ Drop the size as we don't need it - decode-int drop decode-int drop - dup 0= - until - 3drop - 0 exit - else - 0 - then - ; - -\ Get region size for BAR reg -: pci-bar-size@ ( bar-reg -- size ) - " reg" active-package get-package-property 0= if - begin - decode-phys \ ( reg prop prop-len phys.lo phys.mid phys.hi ) - ff and 5 pick = if - 2drop decode-int drop - decode-int - >r 3drop r> - exit - else - 2drop decode-int drop - decode-int drop - then - dup 0= - until - 3drop - 0 \ default size of 0 if BAR not found - then - ; - -\ Get base address for configured BAR reg -: pci-bar-base@ ( bar-reg -- addr.lo addr.hi -1 | 0 ) +\ Get PCI physical address and size for configured BAR reg +: pci-bar>pci-addr ( bar-reg -- addr.lo addr.mid addr.hi size -1 | 0 ) " assigned-addresses" active-package get-package-property 0= if begin decode-phys \ ( reg prop prop-len phys.lo phys.mid phys.hi ) - ff and 5 pick = if - >r >r 3drop r> r> + dup ff and 6 pick = if + >r >r >r rot drop + decode-int drop decode-int + -rot 2drop + r> swap r> r> rot -1 exit else - 2drop + 3drop then \ Drop the size as we don't need it decode-int drop decode-int drop @@ -77,16 +37,4 @@ then ; -\ Get PCI bus address and size for configured BAR reg -: pci-bar>pci-region ( bar-reg -- addr.lo addr.hi size ) - dup - >r pci-bar-offset@ if - swap r@ pci-bar-base@ if - swap d+ - then - swap r@ pci-bar-size@ - then - r> drop - ; - [THEN] diff --git a/roms/openbios/drivers/pci.h b/roms/openbios/drivers/pci.h index 84a2b2cf6..d5aa5f84a 100644 --- a/roms/openbios/drivers/pci.h +++ b/roms/openbios/drivers/pci.h @@ -59,6 +59,15 @@ #define PCI_MIN_GNT 0x3e /* 8 bits */ #define PCI_MAX_LAT 0x3f /* 8 bits */ +#define PCI_RANGE_RELOCATABLE 0x80000000 +#define PCI_RANGE_PREFETCHABLE 0x40000000 +#define PCI_RANGE_ALIASED 0x20000000 +#define PCI_RANGE_TYPE_MASK 0x03000000 +#define PCI_RANGE_MMIO_64BIT 0x03000000 +#define PCI_RANGE_MMIO 0x02000000 +#define PCI_RANGE_IOPORT 0x01000000 +#define PCI_RANGE_CONFIG 0x00000000 + typedef struct { u16 signature; u8 reserved[0x16]; diff --git a/roms/openbios/drivers/sbus.c b/roms/openbios/drivers/sbus.c index a9b26c0a0..4caa59aaf 100644 --- a/roms/openbios/drivers/sbus.c +++ b/roms/openbios/drivers/sbus.c @@ -369,31 +369,6 @@ sbus_probe_slot_ss600mp(unsigned int slot, uint64_t base) } } -static void -ob_sbus_open(void) -{ - int ret=1; - RET ( -ret ); -} - -static void -ob_sbus_close(void) -{ - selfword("close-deblocker"); -} - -static void -ob_sbus_initialize(void) -{ -} - - -NODE_METHODS(ob_sbus_node) = { - { NULL, ob_sbus_initialize }, - { "open", ob_sbus_open }, - { "close", ob_sbus_close }, -}; - struct sbus_offset { int slot, type; uint64_t base; diff --git a/roms/openbios/drivers/usbohci_private.h b/roms/openbios/drivers/usbohci_private.h index b3a723e21..99c964100 100644 --- a/roms/openbios/drivers/usbohci_private.h +++ b/roms/openbios/drivers/usbohci_private.h @@ -43,7 +43,7 @@ // FIXME: fake typedef enum { CMD} reg; - enum { + extern enum { NumberDownstreamPorts = 1<<0, PowerSwitchingMode = 1<<8, NoPowerSwitching = 1<<9, @@ -53,17 +53,17 @@ PowerOnToPowerGoodTime = 1<<24 } HcRhDescriptorAReg; - enum { + extern enum { NumberDownstreamPortsMask = MASK(0, 8), PowerOnToPowerGoodTimeMask = MASK(24, 8) } HcRhDescriptorAMask; - enum { + extern enum { DeviceRemovable = 1<<0, PortPowerControlMask = 1<<16 } HcRhDescriptorBReg; - enum { + extern enum { CurrentConnectStatus = 1<<0, PortEnableStatus = 1<<1, PortSuspendStatus = 1<<2, @@ -77,7 +77,7 @@ PortOverCurrentIndicatorChange = 1<<19, PortResetStatusChange = 1<<20 } HcRhPortStatusRead; - enum { + extern enum { ClearPortEnable = 1<<0, SetPortEnable = 1<<1, SetPortSuspend = 1<<2, @@ -87,7 +87,7 @@ ClearPortPower = 1<<9, } HcRhPortStatusSet; - enum { + extern enum { LocalPowerStatus = 1<<0, OverCurrentIndicator = 1<<1, DeviceRemoteWakeupEnable = 1<<15, @@ -96,18 +96,18 @@ ClearRemoteWakeupEnable = 1<<31 } HcRhStatusReg; - enum { + extern enum { FrameInterval = 1<<0, FSLargestDataPacket = 1<<16, FrameIntervalToggle = 1<<31 } HcFmIntervalOffset; - enum { + extern enum { FrameIntervalMask = MASK(0, 14), FSLargestDataPacketMask = MASK(16, 15), FrameIntervalToggleMask = MASK(31, 1) } HcFmIntervalMask; - enum { + extern enum { ControlBulkServiceRatio = 1<<0, PeriodicListEnable = 1<<2, IsochronousEnable = 1<<3, @@ -119,7 +119,7 @@ RemoteWakeupEnable = 1<<10 } HcControlReg; - enum { + extern enum { ControlBulkServiceRatioMask = MASK(0, 2), HostControllerFunctionalStateMask = MASK(6, 2) } HcControlMask; @@ -131,7 +131,7 @@ USBSuspend = 3*HostControllerFunctionalState }; - enum { + extern enum { HostControllerReset = 1<<0, ControlListFilled = 1<<1, BulkListFilled = 1<<2, @@ -139,16 +139,16 @@ SchedulingOverrunCount = 1<<16 } HcCommandStatusReg; - enum { + extern enum { SchedulingOverrunCountMask = MASK(16, 2) } HcCommandStatusMask; - enum { + extern enum { FrameRemaining = 1<<0, FrameRemainingToggle = 1<<31 } HcFmRemainingReg; - enum { + extern enum { SchedulingOverrung = 1<<0, WritebackDoneHead = 1<<1, StartofFrame = 1<<2, diff --git a/roms/openbios/drivers/vga.fs b/roms/openbios/drivers/vga.fs index ec4c6c5f1..29a043a7a 100644 --- a/roms/openbios/drivers/vga.fs +++ b/roms/openbios/drivers/vga.fs @@ -109,16 +109,17 @@ h# 1 constant VBE_DISPI_ENABLED \ PCI \ -" pci-bar>pci-region" (find-xt) value pci-bar>pci-region-xt -: pci-bar>pci-region pci-bar>pci-region-xt execute ; +" pci-bar>pci-addr" (find-xt) value pci-bar>pci-addr-xt +: pci-bar>pci-addr pci-bar>pci-addr-xt execute ; h# 10 constant cfg-bar0 \ Framebuffer BAR -1 value fb-addr : map-fb ( -- ) - cfg-bar0 pci-bar>pci-region \ ( pci-addr.lo pci-addr.hi size ) - " pci-map-in" $call-parent - to fb-addr + cfg-bar0 pci-bar>pci-addr if \ ( pci-addr.lo pci-addr.mid pci-addr.hi size ) + " pci-map-in" $call-parent + to fb-addr + then ; \ diff --git a/roms/openbios/forth/lib/string.fs b/roms/openbios/forth/lib/string.fs index eb6474917..f97db232f 100644 --- a/roms/openbios/forth/lib/string.fs +++ b/roms/openbios/forth/lib/string.fs @@ -125,3 +125,17 @@ : parse-hex ( str len -- value ) base @ hex -rot $number if 0 then swap base ! ; + + +\ ----------------------------------------------------- +\ miscellaneous functions +\ ----------------------------------------------------- + +: rot13 ( c - c ) + dup upc [char] A [char] M between if d# 13 + exit then + dup upc [char] N [char] Z between if d# 13 - then +; + +: rot13-str ( str len -- newstr len ) + strdup 2dup bounds ?do i c@ rot13 i c! loop +; diff --git a/roms/openbios/forth/system/ciface.fs b/roms/openbios/forth/system/ciface.fs index fd6c54efd..85a607627 100644 --- a/roms/openbios/forth/system/ciface.fs +++ b/roms/openbios/forth/system/ciface.fs @@ -326,6 +326,14 @@ external : exit ( -- ) ." EXIT" + + \ Execute (exit) hook if one exists + s" (exit)" $find if + execute + else + 2drop + then + outer-interpreter ; diff --git a/roms/openbios/include/arch/ppc/types.h b/roms/openbios/include/arch/ppc/types.h index 69b3db405..b2246d060 100644 --- a/roms/openbios/include/arch/ppc/types.h +++ b/roms/openbios/include/arch/ppc/types.h @@ -84,21 +84,13 @@ typedef uint32_t prom_uarg_t; /* size named types */ typedef unsigned char u8; -typedef unsigned char __u8; typedef unsigned short u16; -typedef unsigned short __u16; typedef unsigned int u32; -typedef unsigned int __u32; typedef unsigned long long u64; -typedef unsigned long long __u64; typedef signed char s8; -typedef signed char __s8; typedef short s16; -typedef short __s16; typedef int s32; -typedef int __s32; typedef long long s64; -typedef long long __s64; #endif diff --git a/roms/openbios/include/arch/sparc64/io.h b/roms/openbios/include/arch/sparc64/io.h index 2e4dfa37f..0f1a73284 100644 --- a/roms/openbios/include/arch/sparc64/io.h +++ b/roms/openbios/include/arch/sparc64/io.h @@ -9,7 +9,7 @@ extern unsigned long va_shift; // Set in entry.S // Defined in ldscript -extern char _start, _data, _stack, _estack, _end, _iomem; +extern char _start, _data, _stack, _estack, _fcstack, _efcstack, _end, _iomem; // XXX check use and merge #define phys_to_virt(phys) ((void *) ((unsigned long) (phys))) diff --git a/roms/openbios/include/libopenbios/bindings.h b/roms/openbios/include/libopenbios/bindings.h index de9c77520..4ec978912 100644 --- a/roms/openbios/include/libopenbios/bindings.h +++ b/roms/openbios/include/libopenbios/bindings.h @@ -56,6 +56,7 @@ extern ihandle_t open_package( const char *argstr, phandle_t ph ); extern ihandle_t open_dev( const char *spec ); extern void close_package( ihandle_t ih ); extern void close_dev( ihandle_t ih ); +extern char *get_path_from_ph( phandle_t ph ); /* property access */ extern void set_property( phandle_t ph, const char *name, diff --git a/roms/openbios/libopenbios/bindings.c b/roms/openbios/libopenbios/bindings.c index 5323421f5..4f7a99379 100644 --- a/roms/openbios/libopenbios/bindings.c +++ b/roms/openbios/libopenbios/bindings.c @@ -366,6 +366,14 @@ find_dev( const char *path ) return ret; } +char * +get_path_from_ph( phandle_t ph ) +{ + PUSH(ph); + fword("get-package-path"); + return pop_fstr_copy(); +} + phandle_t dt_iter_begin( void ) { diff --git a/roms/seabios/.version b/roms/seabios/.version index a96337339..89c0c6acb 100644 --- a/roms/seabios/.version +++ b/roms/seabios/.version @@ -1 +1 @@ -rel-1.8.2-0-g33fbe13 +rel-1.9.1-0-gb3ef39f diff --git a/roms/seabios/Makefile b/roms/seabios/Makefile index 83cdff377..4e4092d07 100644 --- a/roms/seabios/Makefile +++ b/roms/seabios/Makefile @@ -34,15 +34,16 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \ hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \ hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \ hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \ - hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \ hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c SRC16=$(SRCBOTH) -SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c romfile.c x86.c optionroms.c \ - pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c \ +SRC32FLAT=$(SRCBOTH) post.c e820map.c malloc.c romfile.c x86.c optionroms.c \ + pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c tcgbios.c sha1.c \ hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c hw/sdcard.c \ - fw/coreboot.c fw/lzmadecode.c fw/csm.c fw/biostables.c \ + fw/coreboot.c fw/lzmadecode.c fw/multiboot.c fw/csm.c fw/biostables.c \ fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/smp.c fw/mtrr.c fw/xen.c \ - fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c + fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c \ + hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \ + hw/tpm_drivers.c SRC32SEG=string.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio.c DIRS=src src/hw src/fw vgasrc @@ -50,6 +51,8 @@ DIRS=src src/hw src/fw vgasrc cc-option=$(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`" \ ; then echo "$(2)"; else echo "$(3)"; fi ;) +EXTRAVERSION= + CPPFLAGS = -P -MD -MT $@ COMMONCFLAGS := -I$(OUT) -Isrc -Os -MD -g \ @@ -62,6 +65,7 @@ COMMONCFLAGS := -I$(OUT) -Isrc -Os -MD -g \ COMMONCFLAGS += $(call cc-option,$(CC),-nopie,) COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,) +COMMONCFLAGS += $(call cc-option,$(CC),-fstack-check=no,) COMMA := , CFLAGS32FLAT := $(COMMONCFLAGS) -DMODE16=0 -DMODESEGMENT=0 @@ -152,10 +156,10 @@ $(OUT)romlayout.o: src/romlayout.S $(OUT)autoconf.h $(OUT)asm-offsets.h @echo " Compiling (16bit) $@" $(Q)$(CC) $(CFLAGS16) -c -D__ASSEMBLY__ $< -o $@ -$(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)ccode16.o $(OUT)romlayout.o scripts/layoutrom.py scripts/buildversion.sh +$(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)ccode16.o $(OUT)romlayout.o src/version.c scripts/layoutrom.py scripts/buildversion.py @echo " Building ld scripts" - $(Q)BUILD_VERSION="$(VERSION)" ./scripts/buildversion.sh $(OUT)version.c - $(Q)$(CC) $(CFLAGS32FLAT) -c $(OUT)version.c -o $(OUT)version.o + $(Q)$(PYTHON) ./scripts/buildversion.py -e "$(EXTRAVERSION)" -t "$(CC);$(AS);$(LD);$(OBJCOPY);$(OBJDUMP);$(STRIP)" $(OUT)autoversion.h + $(Q)$(CC) $(CFLAGS32FLAT) -c src/version.c -o $(OUT)version.o $(Q)$(LD) $(LD32BIT_FLAG) -r $(OUT)ccode32flat.o $(OUT)version.o -o $(OUT)code32flat.o $(Q)$(LD) $(LD32BIT_FLAG) -r $(OUT)ccode16.o $(OUT)romlayout.o -o $(OUT)code16.o $(Q)$(OBJDUMP) -thr $(OUT)code32flat.o > $(OUT)code32flat.o.objdump @@ -177,7 +181,7 @@ $(OUT)rom32seg.o: $(OUT)code32seg.o $(OUT)romlayout32seg.lds $(OUT)rom.o: $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o $(OUT)romlayout32flat.lds @echo " Linking $@" - $(Q)$(LD) -T $(OUT)romlayout32flat.lds $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o -o $@ + $(Q)$(LD) -N -T $(OUT)romlayout32flat.lds $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o -o $@ $(OUT)bios.bin.prep: $(OUT)rom.o scripts/checkrom.py @echo " Prepping $@" @@ -224,10 +228,10 @@ $(OUT)vgaentry.o: vgasrc/vgaentry.S $(OUT)autoconf.h $(OUT)asm-offsets.h @echo " Compiling (16bit) $@" $(Q)$(CC) $(CFLAGS16) -c -D__ASSEMBLY__ $< -o $@ -$(OUT)vgarom.o: $(OUT)vgaccode16.o $(OUT)vgaentry.o $(OUT)vgasrc/vgalayout.lds scripts/buildversion.sh +$(OUT)vgarom.o: $(OUT)vgaccode16.o $(OUT)vgaentry.o $(OUT)vgasrc/vgalayout.lds vgasrc/vgaversion.c scripts/buildversion.py @echo " Linking $@" - $(Q)BUILD_VERSION="$(VERSION)" ./scripts/buildversion.sh $(OUT)vgaversion.c VAR16 - $(Q)$(CC) $(CFLAGS16) -c $(OUT)vgaversion.c -o $(OUT)vgaversion.o + $(Q)$(PYTHON) ./scripts/buildversion.py -e "$(EXTRAVERSION)" -t "$(CC);$(AS);$(LD);$(OBJCOPY);$(OBJDUMP);$(STRIP)" $(OUT)autovgaversion.h + $(Q)$(CC) $(CFLAGS16) -c vgasrc/vgaversion.c -o $(OUT)vgaversion.o $(Q)$(LD) --gc-sections -T $(OUT)vgasrc/vgalayout.lds $(OUT)vgaccode16.o $(OUT)vgaentry.o $(OUT)vgaversion.o -o $@ $(OUT)vgabios.bin.raw: $(OUT)vgarom.o diff --git a/roms/seabios/docs/Build_overview.md b/roms/seabios/docs/Build_overview.md index 26db22691..8c6b2f458 100644 --- a/roms/seabios/docs/Build_overview.md +++ b/roms/seabios/docs/Build_overview.md @@ -52,6 +52,34 @@ CSM_ENABLE'. The SeaBIOS binary will be included as a discrete file within the 'Flash Volume' which is created, and there are tools which will extract it and allow it to be replaced. +Distribution builds +=================== + +If one is building a binary version of SeaBIOS as part of a package +(such as an rpm) or for wide distribution, please provide the +EXTRAVERSION field during the build. For example: + +`make EXTRAVERSION="-${RPM_PACKAGE_RELEASE}"` + +The EXTRAVERSION field should provide the package version (if +applicable) and the name of the distribution (if that's not already +obvious from the package version). This string will be appended to the +main SeaBIOS version. The above information helps SeaBIOS developers +correlate defect reports to the source code and build environment. + +If one is building a binary in a build environment that does not have +access to the git tool or does not have the full SeaBIOS git repo +available, then please use an official SeaBIOS release tar file as +source. If building from a snapshot (where there is no official +SeaBIOS tar) then one should generate a snapshot tar file on a machine +that does support git using the scripts/tarball.sh tool. For example: + +`scripts/tarball.sh` + +The tarball.sh script encodes version information in the resulting tar +file which the build can extract and include in the final binary. The +above EXTRAVERSION field should still be set when building from a tar. + Overview of files in the repository =================================== @@ -61,11 +89,7 @@ drivers. The **src/fw/** directory contains source code for platform firmware initialization. The **src/std/** directory contains header files describing standard bios, firmware, and hardware interfaces. -The **vgasrc/** directory contains code for VGA BIOS implementations. -This code is separate from the main BIOS code in the src/ directory. -When the build is configured to produce a VGA BIOS the resulting -binary is found in out/vgabios.bin. The VGA BIOS code is always -compiled in 16bit mode. +The **vgasrc/** directory contains code for [SeaVGABIOS](SeaVGABIOS). The **scripts/** directory contains helper utilities for manipulating and building the final roms. diff --git a/roms/seabios/docs/Contributing.md b/roms/seabios/docs/Contributing.md new file mode 100644 index 000000000..d0f2b5b5e --- /dev/null +++ b/roms/seabios/docs/Contributing.md @@ -0,0 +1,20 @@ +SeaBIOS welcomes contributions of code (either fixing bugs or adding +new functionality). At a high level, the process to contribute a +change is: + +1. [Obtain](Download) the current code and documentation +2. Enhance and test the code locally +3. Submit changes to the SeaBIOS [mailing list](Mailinglist) as a + patch +4. Receive feedback, answer questions, and possibly provide updated + patches +5. When accepted, a maintainer (Kevin O'Connor or Gerd Hoffman) will + commit the change to the master SeaBIOS repository + +The SeaBIOS patch submission process is similar to the +[QEMU process](http://wiki.qemu.org/Contribute/SubmitAPatch). Please +review the QEMU process for more details and tips on the best way to +submit patches. The SeaBIOS C code does follow a slightly different +coding style from QEMU (eg, mixed code and C99 style variable +declarations are encouraged, braces are not required around single +statement blocks), however patches in the QEMU style are acceptable. diff --git a/roms/seabios/docs/Debugging.md b/roms/seabios/docs/Debugging.md index 03567de4d..7ab5d02d8 100644 --- a/roms/seabios/docs/Debugging.md +++ b/roms/seabios/docs/Debugging.md @@ -55,8 +55,10 @@ rate. The tool can also timestamp the messages from the QEMU debug port. To use with QEMU run the following: -`mkfifo qemudebugpipe`\ -`qemu -chardev pipe,path=qemudebugpipe,id=seabios -device isa-debugcon,iobase=0x402,chardev=seabios ...` +``` +mkfifo qemudebugpipe +qemu -chardev pipe,path=qemudebugpipe,id=seabios -device isa-debugcon,iobase=0x402,chardev=seabios ... +``` and then in another session: @@ -84,20 +86,23 @@ bios 16bit code) or out/rom.o (to debug bios 32bit code). For example: `gdb out/rom16.o` -Once in gdb, use the command "target remote localhost:1234" to have +Once in gdb, use the command `target remote localhost:1234` to have gdb connect to QEMU. See the QEMU documentation for more information on using gdb and QEMU in this mode. -When debugging 16bit code, also run the following commands in gdb: +When debugging 16bit code it is necessary to load the 16bit symbols +twice in order for gdb to properly handle break points. To do this, +run the following command `objcopy --adjust-vma 0xf0000 out/rom16.o +rom16offset.o` and then run the following in gdb: -`set architecture i8086`\ -`add-symbol-file out/rom16.o 0xf0000` +``` +set architecture i8086 +add-symbol-file rom16offset.o 0 +``` -The second command loads the 16bit symbols a second time at an offset -of 0xf0000, which helps gdb set and catch breakpoints correctly. - -To debug a VGA BIOS image, run "gdb out/vgarom.o" add use the gdb -command "add-symbol-file out/vgarom.o 0xc0000" to load the 16bit VGA +To debug a VGA BIOS image, run `gdb out/vgarom.o`, create a +vgaromoffset.o file with offset 0xc0000, add use the gdb +command `add-symbol-file out/vgaromoffset.o 0` to load the 16bit VGA BIOS symbols twice. If debugging the 32bit SeaBIOS initialization code with gdb, note that diff --git a/roms/seabios/docs/Developer_Documentation.md b/roms/seabios/docs/Developer_Documentation.md index d50455d36..24bf48a3e 100644 --- a/roms/seabios/docs/Developer_Documentation.md +++ b/roms/seabios/docs/Developer_Documentation.md @@ -10,15 +10,16 @@ page. See details on [building SeaBIOS](Build overview). There is also information on the SeaBIOS [Memory Model](Memory Model). - Along with information on SeaBIOS [Execution and code flow](Execution -and code flow). +and code flow). A description of the process of linking the final +SeaBIOS binary is available at [Linking overview](Linking overview). -A description of the process of linking the final SeaBIOS binary is -available at [Linking overview](Linking overview). +The list of available runtime configuration items is at +[runtime config](Runtime_config). To debug SeaBIOS and report problems see SeaBIOS -[debugging](Debugging). +[debugging](Debugging). To contribute changes to SeaBIOS see +[contributing](Contributing). Useful links to specifications is available at [Developer links](Developer links). diff --git a/roms/seabios/docs/Download.md b/roms/seabios/docs/Download.md index a49c6fb74..9b1492ac5 100644 --- a/roms/seabios/docs/Download.md +++ b/roms/seabios/docs/Download.md @@ -9,8 +9,10 @@ The SeaBIOS project uses the [git](http://git-scm.com/) revision control system. To download the latest source from revision control, run: -`$ git clone git://git.seabios.org/seabios.git seabios`\ -`$ cd seabios` +``` +$ git clone git://git.seabios.org/seabios.git seabios +$ cd seabios +``` There's also a [website](http://git.seabios.org/) to browse the latest source code online. diff --git a/roms/seabios/docs/Execution_and_code_flow.md b/roms/seabios/docs/Execution_and_code_flow.md index 9396ecaa4..a54776eef 100644 --- a/roms/seabios/docs/Execution_and_code_flow.md +++ b/roms/seabios/docs/Execution_and_code_flow.md @@ -36,7 +36,7 @@ process. The POST phase itself has several sub-phases. -* The "preinit" sub-phase: code run prior to code relocation. +* The "preinit" sub-phase: code run prior to [code relocation](Linking overview#Code relocation). * The "init" sub-phase: code to initialize internal variables and interfaces. * The "setup" sub-phase: code to setup hardware and drivers. diff --git a/roms/seabios/docs/Linking_overview.md b/roms/seabios/docs/Linking_overview.md index fb938b632..bcb8298c3 100644 --- a/roms/seabios/docs/Linking_overview.md +++ b/roms/seabios/docs/Linking_overview.md @@ -92,15 +92,9 @@ those situations where an address of a C function in another mode is required the build supports symbols with a special "\_cfuncX_" prefix. The layoutrom.py script detects these references and will emit a corresponding symbol definitions in the linker script that points to -the C code of the specified mode. This is typically seen with code -like: - -`extern void _cfunc32flat_process_op(void);`\ -`return call32(_cfunc32flat_process_op, 0, 0);` - -In the above example, when the build finds the symbol -"\_cfunc32flat_process_op" it will emit that symbol with the physical -address of the 32bit "flat" version of the process_op() C function. +the C code of the specified mode. The call32() and stack_hop_back() +macros automatically add the required prefix for C code, but the +prefixes need to be explicitly added in assembler code. Build garbage collection ------------------------ diff --git a/roms/seabios/docs/Releases.md b/roms/seabios/docs/Releases.md index 6a1ecd564..c24d3c0b7 100644 --- a/roms/seabios/docs/Releases.md +++ b/roms/seabios/docs/Releases.md @@ -1,6 +1,25 @@ History of SeaBIOS releases. Please see [download](Download) for information on obtaining these releases. +SeaBIOS 1.9.0 +============= + +Available on 20151117. Major changes in this release: + +* The default boot menu key is now the ESC key (instead of F12) +* Initial support for Trusted Platform Module (TPM) hardware and BIOS calls +* Initial support for chain loading SeaBIOS from Grub (via multiboot + support) +* Initial support for booting from SD cards on real hardware +* virtio 1.0 device support +* The build will no longer include the build hostname or build time on + "clean" builds. This makes the build binaries more "reproducible". +* Basic support for running SeaBIOS on Baytrail Chromebooks +* SeaVGABIOS improvements: + * Improved support for old versions of x86emu (the "leal" + instruction is now emulated) +* Several bug fixes and code cleanups + SeaBIOS 1.8.0 ============= @@ -23,6 +42,16 @@ two release numbers (eg, 1.8) and stable releases will use three numbers (eg, 1.8.1). The prior behavior of using a forth number (eg, 1.7.5.1) for stable releases will no longer be used. +SeaBIOS 1.8.1 +------------- + +Available on 20150316. Stable release containing only bug fixes. + +SeaBIOS 1.8.2 +------------- + +Available on 20150617. Stable release containing only bug fixes. + SeaBIOS 1.7.5 ============= diff --git a/roms/seabios/docs/Runtime_config.md b/roms/seabios/docs/Runtime_config.md new file mode 100644 index 000000000..d6fea2827 --- /dev/null +++ b/roms/seabios/docs/Runtime_config.md @@ -0,0 +1,191 @@ +SeaBIOS can read several configuration items at runtime. On coreboot +the configuration comes from files located in CBFS. When SeaBIOS runs +natively on QEMU the files are passed from QEMU via the fw_cfg +interface. + +This page documents the user visible configuration and control +features that SeaBIOS supports. + +LZMA compression +================ + +On coreboot, when scanning files in CBFS, any filename that ends with +a ".lzma" suffix will be treated as a raw file that is compressed with +the lzma compression algorithm. This works for option ROMs, +configuration files, floppy images, etc. . (This feature should not be +used with embedded payloads - to compress payloads, use the standard +section based compression algorithm that is built into the payload +specification.) + +For example, the file **pci1106,3344.rom.lzma** would be treated the +same as **pci1106,3344.rom**, but will be automatically uncompressed +when accessed. + +A file is typically compressed with the lzma compression command line +tool. For example: + +`lzma -zc /path/to/somefile.bin > somefile.bin.lzma` + +However, some recent versions of lzma no longer supply an uncompressed +file size in the lzma header. (They instead populate the field with +zero.) Unfortunately, SeaBIOS requires the uncompressed file size, so +it may be necessary to use a different version of the lzma tool. + +File aliases +============ + +It is possible to create the equivalent of "symbolic links" so that +one file's content appears under another name. To do this, create a +**links** file with one line per link and each line having the format +of "linkname" and "destname" separated by a space character. For +example, the **links** file may look like: + +``` +pci1234,1000.rom somerom.rom +pci1234,1001.rom somerom.rom +pci1234,1002.rom somerom.rom +``` + +The above example would cause SeaBIOS to treat "pci1234,1000.rom" or +"pci1234,1001.rom" as files with the same content as the file +"somerom.rom". + +Option ROMs +=========== + +SeaBIOS will scan all of the PCI devices in the target machine for +option ROMs on PCI devices. It recognizes option ROMs in files that +have the form **pciVVVV,DDDD.rom**. The VVVV,DDDD should correspond to +the PCI vendor and device id of a device in the machine. If a given +file is found then SeaBIOS will deploy the file instead of attempting +to extract an option ROM from the device. In addition to supplying +option ROMs for on-board devices that do not store their own ROMs, +this mechanism may be used to prevent a ROM on a specific device from +running. + +SeaBIOS always deploys the VGA rom associated with the active VGA +device before any other ROMs. + +In addition, SeaBIOS will also run any file in the directory +**vgaroms/** as a VGA option ROM not specific to a device and files in +**genroms/** as a generic option ROM not specific to a device. The +ROMS in **vgaroms/** are run immediately after running the option ROM +associated with the primary VGA device (if any were found), and the +**genroms/** ROMs are run after all other PCI ROMs are run. + +Bootsplash images +================= + +SeaBIOS can show a custom [JPEG](http://en.wikipedia.org/wiki/JPEG) +image or [BMP](http://en.wikipedia.org/wiki/BMP_file_format) image +during bootup. To enable this, add the JPEG file to flash with the +name **bootsplash.jpg** or BMP file as **bootsplash.bmp**. + +The size of the image determines the video mode to use for showing the +image. Make sure the dimensions of the image exactly correspond to an +available video mode (eg, 640x480, or 1024x768), otherwise it will not +be displayed. + +SeaBIOS will show the image during the wait for the boot menu (if the +boot menu has been disabled, users will not see the image). The image +should probably have "Press ESC for boot menu" embedded in it so users +know they can enter the normal SeaBIOS boot menu. By default, the boot +menu prompt (and thus graphical image) is shown for 2.5 seconds. This +can be customized via a [configuration +parameter](#Other_Configuration_items). + +The JPEG viewer in SeaBIOS uses a simplified decoding algorithm. It +supports most common JPEGs, but does not support all possible formats. +Please see the [trouble reporting section](Debugging) if a valid image +isn't displayed properly. + +Payloads +======== + +On coreboot, SeaBIOS will treat all files found in the **img/** +directory as a coreboot payload. Each payload file will be available +for boot, and one can select from the available payloads in the +bootmenu. SeaBIOS supports both uncompressed and lzma compressed +payloads. + +Floppy images +============= + +It is possible to embed an image of a floppy into a file. SeaBIOS can +then boot from and redirect floppy BIOS calls to the image. This is +mainly useful for legacy software (such as DOS utilities). To use this +feature, place a floppy image into the directory **floppyimg/**. + +Using LZMA file compression with the [.lzma file +suffix](#LZMA_compression) is a useful way to reduce the file +size. Several floppy formats are available: 360K, 1.2MB, 720K, 1.44MB, +2.88MB, 160K, 180K, 320K. + +The floppy image will appear as writable to the system, however all +writes are discarded on reboot. + +When using this system, SeaBIOS reserves high-memory to store the +floppy. The reserved memory is then no longer available for OS use, so +this feature should only be used when needed. + +Configuring boot order +====================== + +The **bootorder** file may be used to configure the boot up order. The +file should be ASCII text and contain one line per boot method. The +description of each boot method follows an [Open +Firmware](https://secure.wikimedia.org/wikipedia/en/wiki/Open_firmware) +device path format. SeaBIOS will attempt to boot from each item in the +file - first line of the file first. + +The easiest way to find the available boot methods is to look for +"Searching bootorder for" in the SeaBIOS debug output. For example, +one may see lines similar to: + +``` +Searching bootorder for: /pci@i0cf8/*@f/drive@1/disk@0 +Searching bootorder for: /pci@i0cf8/*@f,1/drive@2/disk@1 +Searching bootorder for: /pci@i0cf8/usb@10,4/*@2 +``` + +The above represents the patterns SeaBIOS will search for in the +bootorder file. However, it's safe to just copy and paste the pattern +into bootorder. For example, the file: + +``` +/pci@i0cf8/usb@10,4/*@2 +/pci@i0cf8/*@f/drive@1/disk@0 +``` + +will instruct SeaBIOS to attempt to boot from the given USB drive +first and then attempt the given ATA harddrive second. + +SeaBIOS also supports a special "HALT" directive. If a line that +contains "HALT" is found in the bootorder file then SeaBIOS will (by +default) only attempt to boot from devices explicitly listed above +HALT in the file. + +Other Configuration items +========================= + +There are several additional configuration options available in the +**etc/** directory. + +| Filename | Description +|---------------------|--------------------------------------------------- +| show-boot-menu | Controls the display of the boot menu. Set to 0 to disable the boot menu. +| boot-menu-message | Customize the text boot menu message. Normally, when in text mode SeaBIOS will report the string "\\nPress ESC for boot menu.\\n\\n". This field allows the string to be changed. (This is a string field, and is added as a file containing the raw string.) +| boot-menu-key | Controls which key activates the boot menu. The value stored is the DOS scan code (eg, 0x86 for F12, 0x01 for Esc). If this field is set, be sure to also customize the **boot-menu-message** field above. +| boot-menu-wait | Amount of time (in milliseconds) to wait at the boot menu prompt before selecting the default boot. +| boot-fail-wait | If no boot devices are found SeaBIOS will reboot after 60 seconds. Set this to the amount of time (in milliseconds) to customize the reboot delay or set to -1 to disable rebooting when no boot devices are found +| extra-pci-roots | If the target machine has multiple independent root buses set this to a positive value. The SeaBIOS PCI probe will then search for the given number of extra root buses. +| ps2-keyboard-spinup | Some laptops that emulate PS2 keyboards don't respond to keyboard commands immediately after powering on. One may specify the amount of time (in milliseconds) here to allow as additional time for the keyboard to become responsive. When this field is set, SeaBIOS will repeatedly attempt to detect the keyboard until the keyboard is found or the specified timeout is reached. +| optionroms-checksum | Option ROMs are required to have correct checksums. However, some option ROMs in the wild don't correctly follow the specifications and have bad checksums. Set this to a zero value to allow SeaBIOS to execute them anyways. +| pci-optionrom-exec | Controls option ROM execution for roms found on PCI devices (as opposed to roms found in CBFS/fw_cfg). Valid values are 0: Execute no ROMs, 1: Execute only VGA ROMs, 2: Execute all ROMs. The default is 2 (execute all ROMs). +| s3-resume-vga-init | Set this to a non-zero value to instruct SeaBIOS to run the vga rom on an S3 resume. +| screen-and-debug | Set this to a zero value to instruct SeaBIOS to not write characters it sends to the screen to the debug ports. This can be useful when using sgabios. +| advertise-serial-debug-port | If using a serial debug port, one can set this file to a zero value to prevent SeaBIOS from listing that serial port as available for operating system use. This can be useful when running old DOS programs that are known to reset the baud rate of all advertised serial ports. +| floppy0 | Set this to the type of the first floppy drive in the system (only type 4 for 3.5 inch drives is supported). +| floppy1 | The type of the second floppy drive in the system. See the description of **floppy0** for more info. +| threads | By default, SeaBIOS will parallelize hardware initialization during bootup to reduce boot time. Multiple hardware devices can be initialized in parallel between vga initialization and option rom initialization. One can set this file to a value of zero to force hardware initialization to run serially. Alternatively, one can set this file to 2 to enable early hardware initialization that runs in parallel with vga, option rom initialization, and the boot menu. +| sdcard* | One may create one or more files with an "sdcard" prefix (eg, "etc/sdcard0") with the physical memory address of an SDHCI controller (one memory address per file). This may be useful for SDHCI controllers that do not appear as PCI devices, but are mapped to a consistent memory address. diff --git a/roms/seabios/docs/SeaBIOS.md b/roms/seabios/docs/SeaBIOS.md index 831bfced9..e24913a64 100644 --- a/roms/seabios/docs/SeaBIOS.md +++ b/roms/seabios/docs/SeaBIOS.md @@ -10,6 +10,8 @@ information on using SeaBIOS in coreboot. Please see the [releases](Releases) page for information on recent releases. See the [download](Download) page to obtain SeaBIOS. +[SeaVGABIOS](SeaVGABIOS) is a sub-project of SeaBIOS. + Please join the [mailing list](Mailinglist) to contribute to SeaBIOS. Information on the internals of SeaBIOS is available on the [Developer Documentation](Developer Documentation) page. diff --git a/roms/seabios/docs/SeaVGABIOS.md b/roms/seabios/docs/SeaVGABIOS.md new file mode 100644 index 000000000..7ec27804d --- /dev/null +++ b/roms/seabios/docs/SeaVGABIOS.md @@ -0,0 +1,39 @@ +SeaVGABIOS is a sub-project of the SeaBIOS project - it is an open +source implementation of a 16bit X86 +[VGA BIOS](http://en.wikipedia.org/wiki/Video_BIOS). SeaVGABIOS is the +default VGA BIOS on [QEMU](http://www.qemu.org/). SeaVGABIOS can also +run natively on some X86 VGA hardware with +[coreboot](http://www.coreboot.org/). + +Building SeaVGABIOS +=================== + +To build SeaVGABIOS, obtain the [code](Download), run `make +menuconfig` and select the type of VGA BIOS to build in the "VGA ROM" +menu. Once selected, run `make` and the final VGA BIOS binary will be +located in "out/vgabios.bin". + +The choice of available VGA BIOSes within "make menuconfig" is +dependent on whether CONFIG_QEMU, CONFIG_COREBOOT, or CONFIG_CSM is +selected. Also, the debug options under the "Debugging" menu apply to +SeaVGABIOS. All other options found in "make menuconfig" apply only to +SeaBIOS and will not impact the SeaVGABIOS build. + +If SeaVGABIOS is needed for multiple different devices (eg, QEMU's +cirrus emulation and QEMU's "dispi" emulation), then one must compile +SeaVGABIOS multiple times with the appropriate config for each build. + +SeaVGABIOS code +=============== + +The source code for SeaVGABIOS is located in the SeaBIOS +[git repository](Download). The main VGA BIOS code is located in the +"vgasrc/" directory. The VGA BIOS code is always compiled in 16bit +mode. + +The SeaVGABIOS builds to a separate binary from the main SeaBIOS +binary, and much of the VGA BIOS code is separate from the main BIOS +code. However, much of the SeaBIOS +[developer documentation](Developer_Documentation) applies to +SeaVGABIOS. To contribute, please join the +[SeaBIOS mailing list](Mailinglist). diff --git a/roms/seabios/scripts/buildversion.py b/roms/seabios/scripts/buildversion.py new file mode 100755 index 000000000..46928984e --- /dev/null +++ b/roms/seabios/scripts/buildversion.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python +# Generate version information for a program +# +# Copyright (C) 2015 Kevin O'Connor <kevin@koconnor.net> +# +# This file may be distributed under the terms of the GNU GPLv3 license. +import sys, os, subprocess, shlex, time, socket, optparse, logging, traceback + +VERSION_FORMAT = """ +/* DO NOT EDIT! This is an autogenerated file. See scripts/buildversion.py. */ +#define BUILD_VERSION "%s" +#define BUILD_TOOLS "%s" +""" + +# Run program and return the specified output +def check_output(prog): + logging.debug("Running %s" % (repr(prog),)) + try: + process = subprocess.Popen(shlex.split(prog), stdout=subprocess.PIPE) + output = process.communicate()[0] + retcode = process.poll() + except OSError: + logging.debug("Exception on run: %s" % (traceback.format_exc(),)) + return "" + logging.debug("Got (code=%s): %s" % (retcode, repr(output))) + if retcode: + return "" + try: + return output.decode() + except UnicodeError: + logging.debug("Exception on decode: %s" % (traceback.format_exc(),)) + return "" + +# Obtain version info from "git" program +def git_version(): + if not os.path.exists('.git'): + logging.debug("No '.git' file/directory found") + return "" + ver = check_output("git describe --tags --long --dirty").strip() + logging.debug("Got git version: %s" % (repr(ver),)) + return ver + +# Look for version in a ".version" file. Official release tarballs +# have this file (see scripts/tarball.sh). +def file_version(): + if not os.path.isfile('.version'): + logging.debug("No '.version' file found") + return "" + try: + f = open('.version', 'r') + ver = f.readline().strip() + f.close() + except OSError: + logging.debug("Exception on read: %s" % (traceback.format_exc(),)) + return "" + logging.debug("Got .version: %s" % (repr(ver),)) + return ver + +# Generate an output file with the version information +def write_version(outfile, version, toolstr): + logging.debug("Write file %s and %s" % (repr(version), repr(toolstr))) + sys.stdout.write("Version: %s\n" % (version,)) + f = open(outfile, 'w') + f.write(VERSION_FORMAT % (version, toolstr)) + f.close() + +# Run "tool --version" for each specified tool and extract versions +def tool_versions(tools): + tools = [t.strip() for t in tools.split(';')] + versions = ['', ''] + success = 0 + for tool in tools: + # Extract first line from "tool --version" output + verstr = check_output("%s --version" % (tool,)).split('\n')[0] + # Check if this tool looks like a binutils program + isbinutils = 0 + if verstr.startswith('GNU '): + isbinutils = 1 + verstr = verstr[4:] + # Extract version information and exclude program name + if ' ' not in verstr: + continue + prog, ver = verstr.split(' ', 1) + if not prog or not ver: + continue + # Check for any version conflicts + if versions[isbinutils] and versions[isbinutils] != ver: + logging.debug("Mixed version %s vs %s" % ( + repr(versions[isbinutils]), repr(ver))) + versions[isbinutils] = "mixed" + continue + versions[isbinutils] = ver + success += 1 + cleanbuild = versions[0] and versions[1] and success == len(tools) + return cleanbuild, "gcc: %s binutils: %s" % (versions[0], versions[1]) + +def main(): + usage = "%prog [options] <outputheader.h>" + opts = optparse.OptionParser(usage) + opts.add_option("-e", "--extra", dest="extra", default="", + help="extra version string to append to version") + opts.add_option("-t", "--tools", dest="tools", default="", + help="list of build programs to extract version from") + opts.add_option("-v", action="store_true", dest="verbose", + help="enable debug messages") + + options, args = opts.parse_args() + if len(args) != 1: + opts.error("Incorrect arguments") + outfile = args[0] + if options.verbose: + logging.basicConfig(level=logging.DEBUG) + + cleanbuild, toolstr = tool_versions(options.tools) + + ver = git_version() + cleanbuild = cleanbuild and 'dirty' not in ver + if not ver: + ver = file_version() + # We expect the "extra version" to contain information on the + # distributor and distribution package version (if + # applicable). It is a "clean" build if this is a build from + # an official release tarball and the above info is present. + cleanbuild = cleanbuild and ver and options.extra != "" + if not ver: + ver = "?" + if not cleanbuild: + btime = time.strftime("%Y%m%d_%H%M%S") + hostname = socket.gethostname() + ver = "%s-%s-%s" % (ver, btime, hostname) + write_version(outfile, ver + options.extra, toolstr) + +if __name__ == '__main__': + main() diff --git a/roms/seabios/scripts/buildversion.sh b/roms/seabios/scripts/buildversion.sh deleted file mode 100755 index 516aff5b2..000000000 --- a/roms/seabios/scripts/buildversion.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# Script to generate a C file with version information. -OUTFILE="$1" -VAR16MODE="$2" - -# Extract version info -if [ -z "$BUILD_VERSION" ]; then - if [ -d .git -o -f .git ]; then - VERSION="`git describe --tags --long --dirty`" - elif [ -f .version ]; then - VERSION="`cat .version`" - else - VERSION="?" - fi - VERSION="${VERSION}-`date +"%Y%m%d_%H%M%S"`-`hostname`" -else - VERSION="$BUILD_VERSION" -fi -echo "Version: ${VERSION}" - -# Build header file -if [ "$VAR16MODE" = "VAR16" ]; then - cat > ${OUTFILE} <<EOF -#include "types.h" -char VERSION[] VAR16 = "${VERSION}"; -EOF -else - cat > ${OUTFILE} <<EOF -char VERSION[] = "${VERSION}"; -EOF -fi diff --git a/roms/seabios/scripts/checkrom.py b/roms/seabios/scripts/checkrom.py index 377277db5..aced5e2cf 100755 --- a/roms/seabios/scripts/checkrom.py +++ b/roms/seabios/scripts/checkrom.py @@ -39,7 +39,7 @@ def main(): finalsize = 256*1024 if datasize > finalsize: print("Error! ROM doesn't fit (%d > %d)" % (datasize, finalsize)) - print(" You have to either increate the size (CONFIG_ROM_SIZE)") + print(" You have to either increase the size (CONFIG_ROM_SIZE)") print(" or turn off some features (such as hardware support not") print(" needed) to make it fit. Trying a more recent gcc version") print(" might work too.") diff --git a/roms/seabios/scripts/checkstack.py b/roms/seabios/scripts/checkstack.py index b49b6c8cc..5d9b0bfaf 100755 --- a/roms/seabios/scripts/checkstack.py +++ b/roms/seabios/scripts/checkstack.py @@ -2,7 +2,7 @@ # Script that tries to find how much stack space each function in an # object is using. # -# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net> +# Copyright (C) 2008-2015 Kevin O'Connor <kevin@koconnor.net> # # This file may be distributed under the terms of the GNU GPLv3 license. @@ -26,85 +26,84 @@ OUTPUTDESC = """ # insn_addr:called_function [u+c,t,usage_to_yield_point] """ +class function: + def __init__(self, funcaddr, funcname): + self.funcaddr = funcaddr + self.funcname = funcname + self.basic_stack_usage = 0 + self.max_stack_usage = None + self.yield_usage = -1 + self.max_yield_usage = None + self.total_calls = 0 + # called_funcs = [(insnaddr, calladdr, stackusage), ...] + self.called_funcs = [] + self.subfuncs = {} + # Update function info with a found "yield" point. + def noteYield(self, stackusage): + if self.yield_usage < stackusage: + self.yield_usage = stackusage + # Update function info with a found "call" point. + def noteCall(self, insnaddr, calladdr, stackusage): + if (calladdr, stackusage) in self.subfuncs: + # Already noted a nearly identical call - ignore this one. + return + self.called_funcs.append((insnaddr, calladdr, stackusage)) + self.subfuncs[(calladdr, stackusage)] = 1 + # Find out maximum stack usage for a function -def calcmaxstack(funcs, funcaddr): - info = funcs[funcaddr] - # Find max of all nested calls. - maxusage = info[1] - maxyieldusage = doesyield = 0 - if info[3] is not None: - maxyieldusage = info[3] - doesyield = 1 - info[2] = maxusage - info[4] = info[3] +def calcmaxstack(info, funcs): + if info.max_stack_usage is not None: + return + info.max_stack_usage = max_stack_usage = info.basic_stack_usage + info.max_yield_usage = max_yield_usage = info.yield_usage + total_calls = 0 seenbefore = {} - totcalls = 0 - for insnaddr, calladdr, usage in info[6]: + # Find max of all nested calls. + for insnaddr, calladdr, usage in info.called_funcs: callinfo = funcs.get(calladdr) if callinfo is None: continue - if callinfo[2] is None: - calcmaxstack(funcs, calladdr) - if callinfo[0] not in seenbefore: - seenbefore[callinfo[0]] = 1 - totcalls += 1 + callinfo[5] - funcnameroot = callinfo[0].split('.')[0] + calcmaxstack(callinfo, funcs) + if callinfo.funcname not in seenbefore: + seenbefore[callinfo.funcname] = 1 + total_calls += callinfo.total_calls + 1 + funcnameroot = callinfo.funcname.split('.')[0] if funcnameroot in IGNORE: # This called function is ignored - don't contribute it to # the max stack. continue + totusage = usage + callinfo.max_stack_usage + totyieldusage = usage + callinfo.max_yield_usage if funcnameroot in STACKHOP: - if usage > maxusage: - maxusage = usage - if callinfo[4] is not None: - doesyield = 1 - if usage > maxyieldusage: - maxyieldusage = usage - continue - totusage = usage + callinfo[2] - if totusage > maxusage: - maxusage = totusage - if callinfo[4] is not None: - doesyield = 1 - totyieldusage = usage + callinfo[4] - if totyieldusage > maxyieldusage: - maxyieldusage = totyieldusage - info[2] = maxusage - if doesyield: - info[4] = maxyieldusage - info[5] = totcalls + # Don't count children of this function + totusage = totyieldusage = usage + if totusage > max_stack_usage: + max_stack_usage = totusage + if callinfo.max_yield_usage >= 0 and totyieldusage > max_yield_usage: + max_yield_usage = totyieldusage + info.max_stack_usage = max_stack_usage + info.max_yield_usage = max_yield_usage + info.total_calls = total_calls # Try to arrange output so that functions that call each other are # near each other. def orderfuncs(funcaddrs, availfuncs): - l = [(availfuncs[funcaddr][5], availfuncs[funcaddr][0], funcaddr) + l = [(availfuncs[funcaddr].total_calls + , availfuncs[funcaddr].funcname, funcaddr) for funcaddr in funcaddrs if funcaddr in availfuncs] l.sort() l.reverse() out = [] while l: count, name, funcaddr = l.pop(0) - if funcaddr not in availfuncs: + info = availfuncs.get(funcaddr) + if info is None: continue - calladdrs = [calls[1] for calls in availfuncs[funcaddr][6]] + calladdrs = [calls[1] for calls in info.called_funcs] del availfuncs[funcaddr] - out = out + orderfuncs(calladdrs, availfuncs) + [funcaddr] + out = out + orderfuncs(calladdrs, availfuncs) + [info] return out -# Update function info with a found "yield" point. -def noteYield(info, stackusage): - prevyield = info[3] - if prevyield is None or prevyield < stackusage: - info[3] = stackusage - -# Update function info with a found "call" point. -def noteCall(info, subfuncs, insnaddr, calladdr, stackusage): - if (calladdr, stackusage) in subfuncs: - # Already noted a nearly identical call - ignore this one. - return - info[6].append((insnaddr, calladdr, stackusage)) - subfuncs[(calladdr, stackusage)] = 1 - hex_s = r'[0-9a-f]+' re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$') re_asm = re.compile( @@ -114,11 +113,12 @@ re_asm = re.compile( re_usestack = re.compile( r'^(push[f]?[lw])|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$') -def calc(): - # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage - # , yieldusage, maxyieldusage, totalcalls - # , [(insnaddr, calladdr, stackusage), ...]] - funcs = {-1: ['<indirect>', 0, 0, None, None, 0, []]} +def main(): + unknownfunc = function(None, "<unknown>") + indirectfunc = function(-1, '<indirect>') + unknownfunc.max_stack_usage = indirectfunc.max_stack_usage = 0 + unknownfunc.max_yield_usage = indirectfunc.max_yield_usage = -1 + funcs = {-1: indirectfunc} cur = None atstart = 0 stackusage = 0 @@ -129,99 +129,93 @@ def calc(): if m is not None: # Found function funcaddr = int(m.group('funcaddr'), 16) - funcs[funcaddr] = cur = [m.group('func'), 0, None, None, None, 0, []] + funcs[funcaddr] = cur = function(funcaddr, m.group('func')) stackusage = 0 atstart = 1 - subfuncs = {} continue m = re_asm.match(line) - if m is not None: - insn = m.group('insn') - - im = re_usestack.match(insn) - if im is not None: - if insn.startswith('pushl') or insn.startswith('pushfl'): - stackusage += 4 - continue - elif insn.startswith('pushw') or insn.startswith('pushfw'): - stackusage += 2 - continue - stackusage += int(im.group('num'), 16) - - if atstart: - if '%esp' in insn or insn.startswith('leal'): - # Still part of initial header - continue - cur[1] = stackusage - atstart = 0 - - insnaddr = m.group('insnaddr') - calladdr = m.group('calladdr') - if calladdr is None: - if insn.startswith('lcallw'): - noteCall(cur, subfuncs, insnaddr, -1, stackusage + 4) - noteYield(cur, stackusage + 4) - elif insn.startswith('int'): - noteCall(cur, subfuncs, insnaddr, -1, stackusage + 6) - noteYield(cur, stackusage + 6) - elif insn.startswith('sti'): - noteYield(cur, stackusage) - else: - # misc instruction - continue + if m is None: + #print("other", repr(line)) + continue + insn = m.group('insn') + + im = re_usestack.match(insn) + if im is not None: + if insn.startswith('pushl') or insn.startswith('pushfl'): + stackusage += 4 + continue + elif insn.startswith('pushw') or insn.startswith('pushfw'): + stackusage += 2 + continue + stackusage += int(im.group('num'), 16) + + if atstart: + if '%esp' in insn or insn.startswith('leal'): + # Still part of initial header + continue + cur.basic_stack_usage = stackusage + atstart = 0 + + insnaddr = m.group('insnaddr') + calladdr = m.group('calladdr') + if calladdr is None: + if insn.startswith('lcallw'): + cur.noteCall(insnaddr, -1, stackusage + 4) + cur.noteYield(stackusage + 4) + elif insn.startswith('int'): + cur.noteCall(insnaddr, -1, stackusage + 6) + cur.noteYield(stackusage + 6) + elif insn.startswith('sti'): + cur.noteYield(stackusage) + else: + # misc instruction + continue + else: + # Jump or call insn + calladdr = int(calladdr, 16) + ref = m.group('ref') + if '+' in ref: + # Inter-function jump. + pass + elif insn.startswith('j'): + # Tail call + cur.noteCall(insnaddr, calladdr, 0) + elif insn.startswith('calll'): + cur.noteCall(insnaddr, calladdr, stackusage + 4) + elif insn.startswith('callw'): + cur.noteCall(insnaddr, calladdr, stackusage + 2) else: - # Jump or call insn - calladdr = int(calladdr, 16) - ref = m.group('ref') - if '+' in ref: - # Inter-function jump. - pass - elif insn.startswith('j'): - # Tail call - noteCall(cur, subfuncs, insnaddr, calladdr, 0) - elif insn.startswith('calll'): - noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 4) - elif insn.startswith('callw'): - noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 2) - else: - print("unknown call", ref) - noteCall(cur, subfuncs, insnaddr, calladdr, stackusage) - # Reset stack usage to preamble usage - stackusage = cur[1] - - #print("other", repr(line)) + print("unknown call", ref) + cur.noteCall(insnaddr, calladdr, stackusage) + # Reset stack usage to preamble usage + stackusage = cur.basic_stack_usage # Calculate maxstackusage - for funcaddr, info in funcs.items(): - if info[2] is not None: - continue - calcmaxstack(funcs, funcaddr) + for info in funcs.values(): + calcmaxstack(info, funcs) # Sort functions for output - funcaddrs = orderfuncs(funcs.keys(), funcs.copy()) + funcinfos = orderfuncs(funcs.keys(), funcs.copy()) # Show all functions print(OUTPUTDESC) - for funcaddr in funcaddrs: - name, basicusage, maxusage, yieldusage, maxyieldusage, count, calls = \ - funcs[funcaddr] - if maxusage == 0 and maxyieldusage is None: + for info in funcinfos: + if info.max_stack_usage == 0 and info.max_yield_usage < 0: continue yieldstr = "" - if maxyieldusage is not None: - yieldstr = ",%d" % maxyieldusage - print("\n%s[%d,%d%s]:" % (name, basicusage, maxusage, yieldstr)) - for insnaddr, calladdr, stackusage in calls: - callinfo = funcs.get(calladdr, ("<unknown>", 0, 0, 0, None)) + if info.max_yield_usage >= 0: + yieldstr = ",%d" % info.max_yield_usage + print("\n%s[%d,%d%s]:" % (info.funcname, info.basic_stack_usage + , info.max_stack_usage, yieldstr)) + for insnaddr, calladdr, stackusage in info.called_funcs: + callinfo = funcs.get(calladdr, unknownfunc) yieldstr = "" - if callinfo[4] is not None: - yieldstr = ",%d" % (stackusage + callinfo[4]) + if callinfo.max_yield_usage >= 0: + yieldstr = ",%d" % (stackusage + callinfo.max_yield_usage) print(" %04s:%-40s [%d+%d,%d%s]" % ( - insnaddr, callinfo[0], stackusage, callinfo[1] - , stackusage+callinfo[2], yieldstr)) - -def main(): - calc() + insnaddr, callinfo.funcname, stackusage + , callinfo.basic_stack_usage + , stackusage+callinfo.max_stack_usage, yieldstr)) if __name__ == '__main__': main() diff --git a/roms/seabios/scripts/kconfig/lxdialog/util.c b/roms/seabios/scripts/kconfig/lxdialog/util.c index f7abdeb92..2a0d182e8 100644 --- a/roms/seabios/scripts/kconfig/lxdialog/util.c +++ b/roms/seabios/scripts/kconfig/lxdialog/util.c @@ -376,7 +376,7 @@ void print_title(WINDOW *dialog, const char *title, int width) /* * Print a string of text in a window, automatically wrap around to the * next line if the string is too long to fit on one line. Newline - * characters '\n' are propperly processed. We start on a new line + * characters '\n' are properly processed. We start on a new line * if there is no room for at least 4 nonblanks following a double-space. */ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) diff --git a/roms/seabios/scripts/layoutrom.py b/roms/seabios/scripts/layoutrom.py index dd770fe49..b976fb056 100755 --- a/roms/seabios/scripts/layoutrom.py +++ b/roms/seabios/scripts/layoutrom.py @@ -161,6 +161,7 @@ def getSectionsPrefix(sections, prefix): # The sections (and associated information) to be placed in output rom class LayoutInfo: sections = None + config = None genreloc = None sec32init_start = sec32init_end = sec32init_align = None sec32low_start = sec32low_end = None @@ -172,6 +173,7 @@ class LayoutInfo: # Determine final memory addresses for sections def doLayout(sections, config, genreloc): li = LayoutInfo() + li.config = config li.sections = sections li.genreloc = genreloc # Determine 16bit positions @@ -399,6 +401,10 @@ def writeLinkerScripts(li, out16, out32seg, out32flat): filesections32flat = getSectionsFileid(li.sections, '32flat') out = outXRefs([], exportsyms=li.varlowsyms , forcedelta=li.final_sec32low_start-li.sec32low_start) + multiboot_header = "" + if li.config.get('CONFIG_MULTIBOOT'): + multiboot_header = "LONG(0x1BADB002) LONG(0) LONG(-0x1BADB002)" + sec32all_start -= 3 * 4 out += outXRefs(filesections32flat, exportsyms=[li.entrysym]) + """ _reloc_min_align = 0x%x ; zonefseg_start = 0x%x ; @@ -415,6 +421,7 @@ def writeLinkerScripts(li, out16, out32seg, out32flat): .text code32flat_start : { %s %s +%s code32flat_end = ABSOLUTE(.) ; } :text """ % (li.sec32init_align, @@ -428,6 +435,7 @@ def writeLinkerScripts(li, out16, out32seg, out32flat): li.sec32init_start, li.sec32init_end, sec32all_start, + multiboot_header, relocstr, outRelSections(li.sections, 'code32flat_start')) out = COMMONHEADER + out + COMMONTRAILER + """ diff --git a/roms/seabios/src/Kconfig b/roms/seabios/src/Kconfig index 45ca59cf3..95bf087b8 100644 --- a/roms/seabios/src/Kconfig +++ b/roms/seabios/src/Kconfig @@ -20,7 +20,7 @@ choice Configure for an emulated machine (QEMU, Xen, KVM, or Bochs). config CSM - bool "Build as Compatibilty Support Module for EFI BIOS" + bool "Build as Compatibility Support Module for EFI BIOS" help Configure to be used by EFI firmware as Compatibility Support module (CSM) to provide legacy BIOS services. @@ -96,12 +96,13 @@ endchoice the CBFS filesystem is at a non-standard location (eg, 0xffe00000 if CBFS ends 2Meg below the end of flash). - config FLASH_FLOPPY - depends on COREBOOT_FLASH - bool "Floppy images in CBFS" + config MULTIBOOT + depends on COREBOOT + bool "multiboot support" default y help - Support floppy images in coreboot flash. + Add multiboot header in bios.bin.raw and accept files supplied + as multiboot modules. config ENTRY_EXTRASTACK bool "Use internal stack for 16bit interrupt entry points" default y @@ -160,7 +161,7 @@ menu "Hardware support" help Support for AHCI disk code. config SDCARD - depends on DRIVES && QEMU_HARDWARE + depends on DRIVES bool "SD controllers" default y help @@ -208,11 +209,18 @@ menu "Hardware support" help Support boot from LSI MegaRAID SAS scsi storage. config FLOPPY - depends on DRIVES + depends on DRIVES && HARDWARE_IRQ bool "Floppy controller" default y help Support floppy drive access. + config FLASH_FLOPPY + depends on DRIVES + bool "Floppy images from CBFS or fw_cfg" + default y + help + Support floppy images stored in coreboot flash or from + QEMU fw_cfg. config PS2PORT depends on KEYBOARD || MOUSE @@ -291,6 +299,26 @@ menu "Hardware support" default y help Support parallel ports. This also enables int 17 parallel port calls. + config RTC_TIMER + bool "Real Time Clock (RTC) scheduling" + depends on HARDWARE_IRQ + default y + help + Support MC146818 Real Time Clock chip timer + interrupts. This also enables int 1583 and int 1586 calls. + + Disabling this support does not disable access to the RTC + cmos registers. + + config HARDWARE_IRQ + bool "Hardware interrupts" + default y + help + Program and support hardware interrupts using the i8259 + programmable interrupt controller (PIC). This option must + be enabled in order to support most boot loaders. Only + disable this option if running on peculiar hardware known + not to support irq routing. config USE_SMM depends on QEMU @@ -309,10 +337,16 @@ menu "Hardware support" help Initialize the Memory Type Range Registers (on emulators). config PMTIMER - bool "Use ACPI timer" + bool "Support ACPI timer" default y help - Use the ACPI timer instead of the TSC for timekeeping (on qemu). + Detect and use the ACPI timer for timekeeping. + config TSC_TIMER + bool "Support CPU timestamp counter as timer" + default y + help + Support for using the CPU timestamp counter as an internal + timing source. endmenu menu "BIOS interfaces" @@ -421,6 +455,13 @@ menu "BIOS interfaces" modified by programs. However, some old DOS high memory managers may require the UMB region to be read-only. + config TCGBIOS + depends on S3_RESUME + bool "TPM support and TCG BIOS extensions" + default y + help + Provide TPM support along with TCG BIOS extensions + endmenu menu "BIOS Tables" diff --git a/roms/seabios/src/biosvar.h b/roms/seabios/src/biosvar.h index 58bcbcedb..f61fb6a50 100644 --- a/roms/seabios/src/biosvar.h +++ b/roms/seabios/src/biosvar.h @@ -8,11 +8,12 @@ #include "config.h" // SEG_BDA #include "farptr.h" // GET_FARVAR +#include "memmap.h" // SYMBOL #include "std/bda.h" // struct bios_data_area_s /**************************************************************** - * Interupt vector table + * Interrupt vector table ****************************************************************/ #define GET_IVT(vector) \ @@ -112,13 +113,12 @@ static inline u16 get_global_seg(void) { * "Low" memory variables ****************************************************************/ -extern u8 _zonelow_seg, zonelow_base[]; -#define SEG_LOW ((u32)&_zonelow_seg) +#define SEG_LOW SYMBOL(_zonelow_seg) #if MODESEGMENT #define GET_LOW(var) GET_FARVAR(SEG_LOW, (var)) #define SET_LOW(var, val) SET_FARVAR(SEG_LOW, (var), (val)) -#define LOWFLAT2LOW(var) ((typeof(var))((void*)(var) - (u32)zonelow_base)) +#define LOWFLAT2LOW(var) ((typeof(var))((void*)(var) - SYMBOL(zonelow_base))) #else #define GET_LOW(var) (var) #define SET_LOW(var, val) do { (var) = (val); } while (0) diff --git a/roms/seabios/src/block.c b/roms/seabios/src/block.c index 3f7ecb1d7..1762e2a33 100644 --- a/roms/seabios/src/block.c +++ b/roms/seabios/src/block.c @@ -10,9 +10,16 @@ #include "hw/ata.h" // process_ata_op #include "hw/ahci.h" // process_ahci_op #include "hw/blockcmd.h" // cdb_* +#include "hw/esp-scsi.h" // esp_scsi_process_op +#include "hw/lsi-scsi.h" // lsi_scsi_process_op +#include "hw/megasas.h" // megasas_process_op #include "hw/pci.h" // pci_bdf_to_bus +#include "hw/pvscsi.h" // pvscsi_process_op #include "hw/rtc.h" // rtc_read +#include "hw/usb-msc.h" // usb_process_op +#include "hw/usb-uas.h" // uas_process_op #include "hw/virtio-blk.h" // process_virtio_blk_op +#include "hw/virtio-scsi.h" // virtio_scsi_process_op #include "malloc.h" // malloc_low #include "output.h" // dprintf #include "stacks.h" // stack_hop @@ -67,10 +74,8 @@ get_translation(struct drive_s *drive) u8 type = drive->type; if (CONFIG_QEMU && type == DTYPE_ATA) { // Emulators pass in the translation info via nvram. - u8 ataid = drive->cntl_id; - u8 channel = ataid / 2; - u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + channel/2); - translation >>= 2 * (ataid % 4); + u8 translation = rtc_read(CMOS_BIOS_DISKTRANSFLAG + drive->cntl_id/4); + translation >>= 2 * (drive->cntl_id % 4); translation &= 0x03; return translation; } @@ -282,11 +287,21 @@ map_floppy_drive(struct drive_s *drive) * Extended Disk Drive (EDD) get drive parameters ****************************************************************/ +// flags for bus_iface field in fill_generic_edd() +#define EDD_ISA 0x01 +#define EDD_PCI 0x02 +#define EDD_BUS_MASK 0x0f +#define EDD_ATA 0x10 +#define EDD_SCSI 0x20 +#define EDD_IFACE_MASK 0xf0 + +// Fill in EDD info static int -fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf - , u32 dpte_so, char *iface_type - , int bdf, u8 channel, u16 iobase, u64 device_path) +fill_generic_edd(struct segoff_s edd, struct drive_s *drive_gf + , u32 dpte_so, u8 bus_iface, u32 iface_path, u32 device_path) { + u16 seg = edd.seg; + struct int13dpt_s *param_far = (void*)(edd.offset+0); u16 size = GET_FARVAR(seg, param_far->size); u16 t13 = size == 74; @@ -335,7 +350,7 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf SET_FARVAR(seg, param_far->size, 30); SET_FARVAR(seg, param_far->dpte.segoff, dpte_so); - if (size < 66 || !iface_type) + if (size < 66 || !bus_iface) return DISK_RET_SUCCESS; // EDD 3.x @@ -344,32 +359,22 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf SET_FARVAR(seg, param_far->reserved1, 0); SET_FARVAR(seg, param_far->reserved2, 0); - int i; - for (i=0; i<sizeof(param_far->iface_type); i++) - SET_FARVAR(seg, param_far->iface_type[i], GET_GLOBAL(iface_type[i])); - - if (bdf != -1) { - SET_FARVAR(seg, param_far->host_bus[0], 'P'); - SET_FARVAR(seg, param_far->host_bus[1], 'C'); - SET_FARVAR(seg, param_far->host_bus[2], 'I'); - SET_FARVAR(seg, param_far->host_bus[3], ' '); - - u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8) - | (pci_bdf_to_fn(bdf) << 16)); - if (t13) - path |= channel << 24; - - SET_FARVAR(seg, param_far->iface_path, path); - } else { - // ISA - SET_FARVAR(seg, param_far->host_bus[0], 'I'); - SET_FARVAR(seg, param_far->host_bus[1], 'S'); - SET_FARVAR(seg, param_far->host_bus[2], 'A'); - SET_FARVAR(seg, param_far->host_bus[3], ' '); - - SET_FARVAR(seg, param_far->iface_path, iobase); + const char *host_bus = "ISA "; + if ((bus_iface & EDD_BUS_MASK) == EDD_PCI) { + host_bus = "PCI "; + if (!t13) + // Phoenix v3 spec (pre t13) did not define the PCI channel field + iface_path &= 0x00ffffff; } - + memcpy_far(seg, param_far->host_bus, SEG_BIOS, host_bus + , sizeof(param_far->host_bus)); + SET_FARVAR(seg, param_far->iface_path, iface_path); + + const char *iface_type = "ATA "; + if ((bus_iface & EDD_IFACE_MASK) == EDD_SCSI) + iface_type = "SCSI "; + memcpy_far(seg, param_far->iface_type, SEG_BIOS, iface_type + , sizeof(param_far->iface_type)); if (t13) { SET_FARVAR(seg, param_far->t13.device_path[0], device_path); SET_FARVAR(seg, param_far->t13.device_path[1], 0); @@ -386,10 +391,19 @@ fill_generic_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf return DISK_RET_SUCCESS; } +// Build an EDD "iface_path" field for a PCI device +static u32 +edd_pci_path(u16 bdf, u8 channel) +{ + return (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8) + | (pci_bdf_to_fn(bdf) << 16) | ((u32)channel << 24)); +} + struct dpte_s DefaultDPTE VARLOW; +// EDD info for ATA and ATAPI drives static int -fill_ata_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf) +fill_ata_edd(struct segoff_s edd, struct drive_s *drive_gf) { if (!CONFIG_ATA) return DISK_RET_EPARAM; @@ -440,109 +454,141 @@ fill_ata_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf) u8 sum = checksum_far(SEG_LOW, &DefaultDPTE, 15); SET_LOW(DefaultDPTE.checksum, -sum); + u32 bustype = EDD_ISA, ifpath = iobase1; + if (bdf >= 0) { + bustype = EDD_PCI; + ifpath = edd_pci_path(bdf, channel); + } return fill_generic_edd( - seg, param_far, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff - , "ATA ", bdf, channel, iobase1, slave); + edd, drive_gf, SEGOFF(SEG_LOW, (u32)&DefaultDPTE).segoff + , bustype | EDD_ATA, ifpath, slave); } +// Fill Extended Disk Drive (EDD) "Get drive parameters" info for a drive int noinline -fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf) +fill_edd(struct segoff_s edd, struct drive_s *drive_gf) { switch (GET_GLOBALFLAT(drive_gf->type)) { case DTYPE_ATA: case DTYPE_ATA_ATAPI: - return fill_ata_edd(seg, param_far, drive_gf); + return fill_ata_edd(edd, drive_gf); case DTYPE_VIRTIO_BLK: case DTYPE_VIRTIO_SCSI: return fill_generic_edd( - seg, param_far, drive_gf, 0xffffffff - , "SCSI ", GET_GLOBALFLAT(drive_gf->cntl_id), 0, 0, 0); + edd, drive_gf, 0xffffffff, EDD_PCI | EDD_SCSI + , edd_pci_path(GET_GLOBALFLAT(drive_gf->cntl_id), 0), 0); default: - return fill_generic_edd(seg, param_far, drive_gf, 0, NULL, 0, 0, 0, 0); + return fill_generic_edd(edd, drive_gf, 0, 0, 0, 0); } } /**************************************************************** - * 16bit calling interface + * Disk driver dispatch ****************************************************************/ -int VISIBLE32FLAT -process_atapi_op(struct disk_op_s *op) +// Fallback handler for command requests not implemented by drivers +int +default_process_op(struct disk_op_s *op) { switch (op->command) { - case CMD_WRITE: case CMD_FORMAT: - return DISK_RET_EWRITEPROTECT; + case CMD_RESET: + case CMD_ISREADY: + case CMD_VERIFY: + case CMD_SEEK: + // Return success if the driver doesn't implement these commands + return DISK_RET_SUCCESS; default: - return scsi_process_op(op); + return DISK_RET_EPARAM; } } -// Execute a disk_op request. -int -process_op(struct disk_op_s *op) +// Command dispatch for disk drivers that run in both 16bit and 32bit mode +static int +process_op_both(struct disk_op_s *op) { - ASSERT16(); - int ret, origcount = op->count; - if (origcount * GET_GLOBALFLAT(op->drive_gf->blksize) > 64*1024) { - op->count = 0; - return DISK_RET_EBOUNDARY; - } - u8 type = GET_GLOBALFLAT(op->drive_gf->type); - switch (type) { - case DTYPE_FLOPPY: - ret = process_floppy_op(op); - break; - case DTYPE_ATA: - ret = process_ata_op(op); - break; - case DTYPE_RAMDISK: - ret = process_ramdisk_op(op); - break; - case DTYPE_CDEMU: - ret = process_cdemu_op(op); - break; - case DTYPE_VIRTIO_BLK: - ret = process_virtio_blk_op(op); - break; - case DTYPE_AHCI: ; - extern void _cfunc32flat_process_ahci_op(void); - ret = call32(_cfunc32flat_process_ahci_op - , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); - break; + switch (GET_GLOBALFLAT(op->drive_gf->type)) { case DTYPE_ATA_ATAPI: - ret = process_atapi_op(op); - break; - case DTYPE_AHCI_ATAPI: ; - extern void _cfunc32flat_process_atapi_op(void); - ret = call32(_cfunc32flat_process_atapi_op - , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); - break; - case DTYPE_SDCARD: ; - extern void _cfunc32flat_process_sdcard_op(void); - ret = call32(_cfunc32flat_process_sdcard_op - , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); - break; + return ata_atapi_process_op(op); case DTYPE_USB: + return usb_process_op(op); case DTYPE_UAS: - case DTYPE_VIRTIO_SCSI: + return uas_process_op(op); case DTYPE_LSI_SCSI: + return lsi_scsi_process_op(op); case DTYPE_ESP_SCSI: + return esp_scsi_process_op(op); case DTYPE_MEGASAS: - ret = scsi_process_op(op); - break; + return megasas_process_op(op); + default: + if (!MODESEGMENT) + return DISK_RET_EPARAM; + // In 16bit mode and driver not found - try in 32bit mode + return call32(process_op_32, MAKE_FLATPTR(GET_SEG(SS), op) + , DISK_RET_EPARAM); + } +} + +// Command dispatch for disk drivers that only run in 32bit mode +int VISIBLE32FLAT +process_op_32(struct disk_op_s *op) +{ + ASSERT32FLAT(); + switch (op->drive_gf->type) { + case DTYPE_VIRTIO_BLK: + return virtio_blk_process_op(op); + case DTYPE_AHCI: + return ahci_process_op(op); + case DTYPE_AHCI_ATAPI: + return ahci_atapi_process_op(op); + case DTYPE_SDCARD: + return sdcard_process_op(op); case DTYPE_USB_32: + return usb_process_op(op); case DTYPE_UAS_32: - case DTYPE_PVSCSI: ; - extern void _cfunc32flat_scsi_process_op(void); - ret = call32(_cfunc32flat_scsi_process_op - , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM); - break; + return uas_process_op(op); + case DTYPE_VIRTIO_SCSI: + return virtio_scsi_process_op(op); + case DTYPE_PVSCSI: + return pvscsi_process_op(op); default: - ret = DISK_RET_EPARAM; - break; + return process_op_both(op); } +} + +// Command dispatch for disk drivers that only run in 16bit mode +static int +process_op_16(struct disk_op_s *op) +{ + ASSERT16(); + switch (GET_GLOBALFLAT(op->drive_gf->type)) { + case DTYPE_FLOPPY: + return floppy_process_op(op); + case DTYPE_ATA: + return ata_process_op(op); + case DTYPE_RAMDISK: + return ramdisk_process_op(op); + case DTYPE_CDEMU: + return cdemu_process_op(op); + default: + return process_op_both(op); + } +} + +// Execute a disk_op_s request. +int +process_op(struct disk_op_s *op) +{ + int ret, origcount = op->count; + if (origcount * GET_GLOBALFLAT(op->drive_gf->blksize) > 64*1024) { + op->count = 0; + return DISK_RET_EBOUNDARY; + } + if (MODESEGMENT) + ret = process_op_16(op); + else + ret = process_op_32(op); if (ret && op->count == origcount) // If the count hasn't changed on error, assume no data transferred. op->count = 0; @@ -578,5 +624,5 @@ send_disk_op(struct disk_op_s *op) if (! CONFIG_DRIVES) return -1; - return stack_hop((u32)op, GET_SEG(SS), __send_disk_op); + return stack_hop(__send_disk_op, op, GET_SEG(SS)); } diff --git a/roms/seabios/src/block.h b/roms/seabios/src/block.h index 8182288d4..2ff359fb2 100644 --- a/roms/seabios/src/block.h +++ b/roms/seabios/src/block.h @@ -9,11 +9,19 @@ ****************************************************************/ struct disk_op_s { - u64 lba; void *buf_fl; struct drive_s *drive_gf; - u16 count; u8 command; + u16 count; + union { + // Commands: READ, WRITE, VERIFY, SEEK, FORMAT + u64 lba; + // Commands: SCSI + struct { + u16 blocksize; + void *cdbcmd; + }; + }; }; #define CMD_RESET 0x00 @@ -23,6 +31,7 @@ struct disk_op_s { #define CMD_FORMAT 0x05 #define CMD_SEEK 0x07 #define CMD_ISREADY 0x10 +#define CMD_SCSI 0x20 /**************************************************************** @@ -101,7 +110,8 @@ void map_floppy_drive(struct drive_s *drive); void map_hd_drive(struct drive_s *drive); void map_cd_drive(struct drive_s *drive); struct int13dpt_s; -int fill_edd(u16 seg, struct int13dpt_s *param_far, struct drive_s *drive_gf); +int fill_edd(struct segoff_s edd, struct drive_s *drive_gf); +int default_process_op(struct disk_op_s *op); int process_op(struct disk_op_s *op); int send_disk_op(struct disk_op_s *op); int create_bounce_buf(void); diff --git a/roms/seabios/src/bmp.c b/roms/seabios/src/bmp.c index d8e76b789..96a2b3f22 100644 --- a/roms/seabios/src/bmp.c +++ b/roms/seabios/src/bmp.c @@ -1,6 +1,6 @@ /* * Basic BMP data process and Raw picture data handle functions. -* Could be used to adjust pixel data format, get infomation, etc. +* Could be used to adjust pixel data format, get information, etc. * * Copyright (C) 2011 Wayne Xia <xiawenc@cn.ibm.com> * diff --git a/roms/seabios/src/boot.c b/roms/seabios/src/boot.c index f23e9e154..e0f73a385 100644 --- a/roms/seabios/src/boot.c +++ b/roms/seabios/src/boot.c @@ -19,6 +19,7 @@ #include "std/disk.h" // struct mbr_s #include "string.h" // memset #include "util.h" // irqtimer_calc +#include "tcgbios.h" // tpm_* /**************************************************************** @@ -111,9 +112,9 @@ build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci) if (pci->parent) { p = build_pci_path(p, max, "pci-bridge", pci->parent); } else { - if (pci->rootbus) - p += snprintf(p, max, "/pci-root@%x", pci->rootbus); p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN); + if (pci->rootbus) + p += snprintf(p, buf+max-p, ",%x", pci->rootbus); } int dev = pci_bdf_to_dev(pci->bdf), fn = pci_bdf_to_fn(pci->bdf); @@ -459,8 +460,8 @@ interactive_bootmenu(void) ; char *bootmsg = romfile_loadfile("etc/boot-menu-message", NULL); - int menukey = romfile_loadint("etc/boot-menu-key", 0x86); - printf("%s", bootmsg ?: "\nPress F12 for boot menu.\n\n"); + int menukey = romfile_loadint("etc/boot-menu-key", 1); + printf("%s", bootmsg ?: "\nPress ESC for boot menu.\n\n"); free(bootmsg); u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT); @@ -486,9 +487,15 @@ interactive_bootmenu(void) , strtcpy(desc, pos->description, ARRAY_SIZE(desc))); } - // Get key press + // Get key press. If the menu key is ESC, do not restart boot unless + // 1.5 seconds have passed. Otherwise users (trained by years of + // repeatedly hitting keys to enter the BIOS) will end up hitting ESC + // multiple times and immediately booting the primary boot device. + int esc_accepted_time = irqtimer_calc(menukey == 1 ? 1500 : 0); for (;;) { scan_code = get_keystroke(1000); + if (scan_code == 1 && !irqtimer_check(esc_accepted_time)) + continue; if (scan_code >= 1 && scan_code <= maxmenu+1) break; } @@ -622,6 +629,8 @@ boot_disk(u8 bootdrv, int checksig) } } + tpm_add_bcv(bootdrv, MAKE_FLATPTR(bootseg, 0), 512); + /* Canonicalize bootseg:bootip */ u16 bootip = (bootseg & 0x0fff) << 4; bootseg &= 0xf000; @@ -645,6 +654,9 @@ boot_cdrom(struct drive_s *drive_g) u8 bootdrv = CDEmu.emulated_drive; u16 bootseg = CDEmu.load_segment; + + tpm_add_cdrom(bootdrv, MAKE_FLATPTR(bootseg, 0), 512); + /* Canonicalize bootseg:bootip */ u16 bootip = (bootseg & 0x0fff) << 4; bootseg &= 0xf000; diff --git a/roms/seabios/src/cdrom.c b/roms/seabios/src/cdrom.c index 92f34f42b..a4f31adde 100644 --- a/roms/seabios/src/cdrom.c +++ b/roms/seabios/src/cdrom.c @@ -15,9 +15,7 @@ #include "std/disk.h" // DISK_RET_SUCCESS #include "string.h" // memset #include "util.h" // cdrom_prepboot - -// Locks for removable devices -u8 CDRom_locks[BUILD_MAX_EXTDRIVE] VARLOW; +#include "tcgbios.h" // tpm_* /**************************************************************** @@ -88,7 +86,7 @@ cdemu_read(struct disk_op_s *op) } int -process_cdemu_op(struct disk_op_s *op) +cdemu_process_op(struct disk_op_s *op) { if (!CONFIG_CDROM_EMU) return 0; @@ -99,13 +97,8 @@ process_cdemu_op(struct disk_op_s *op) case CMD_WRITE: case CMD_FORMAT: return DISK_RET_EWRITEPROTECT; - case CMD_VERIFY: - case CMD_RESET: - case CMD_SEEK: - case CMD_ISREADY: - return DISK_RET_SUCCESS; default: - return DISK_RET_EPARAM; + return default_process_op(op); } } @@ -122,7 +115,6 @@ cdrom_prepboot(void) struct drive_s *drive = malloc_fseg(sizeof(*drive)); if (!drive) { warn_noalloc(); - free(drive); return; } cdemu_drive_gf = drive; @@ -158,7 +150,7 @@ cdrom_boot(struct drive_s *drive) dop.lba = 0x11; dop.count = 1; dop.buf_fl = buffer; - ret = scsi_process_op(&dop); + ret = process_op(&dop); if (ret) return 3; @@ -174,7 +166,7 @@ cdrom_boot(struct drive_s *drive) // And we read the Boot Catalog dop.lba = lba; dop.count = 1; - ret = scsi_process_op(&dop); + ret = process_op(&dop); if (ret) return 7; @@ -192,6 +184,9 @@ cdrom_boot(struct drive_s *drive) if (buffer[0x20] != 0x88) return 11; // Bootable + /* measure 2048 bytes (one sector) */ + tpm_add_cdrom_catalog(MAKE_FLATPTR(GET_SEG(SS), buffer), sizeof(buffer)); + // Fill in el-torito cdrom emulation fields. emulated_drive_gf = drive; u8 media = buffer[0x21]; @@ -220,7 +215,7 @@ cdrom_boot(struct drive_s *drive) if (count > 64*1024/CDROM_SECTOR_SIZE) count = 64*1024/CDROM_SECTOR_SIZE; dop.count = count; - ret = scsi_process_op(&dop); + ret = process_op(&dop); if (ret) return 12; nbsectors -= count; diff --git a/roms/seabios/src/clock.c b/roms/seabios/src/clock.c index 9ab0ac026..e83e0f338 100644 --- a/roms/seabios/src/clock.c +++ b/roms/seabios/src/clock.c @@ -8,6 +8,7 @@ #include "biosvar.h" // SET_BDA #include "bregs.h" // struct bregs #include "hw/pic.h" // pic_eoi1 +#include "hw/ps2port.h" // ps2_check_event #include "hw/rtc.h" // rtc_read #include "hw/usb-hid.h" // usb_check_event #include "output.h" // debug_enter @@ -55,7 +56,8 @@ clock_setup(void) } enable_hwirq(0, FUNC16(entry_08)); - enable_hwirq(8, FUNC16(entry_70)); + if (CONFIG_RTC_TIMER) + enable_hwirq(8, FUNC16(entry_70)); } @@ -239,6 +241,16 @@ handle_1a07(struct bregs *regs) set_success(regs); } +static void +handle_1abb(struct bregs *regs) +{ + if (!CONFIG_TCGBIOS) + return; + + dprintf(DEBUG_tcg, "16: Calling tpm_interrupt_handler\n"); + call32(tpm_interrupt_handler32, MAKE_FLATPTR(GET_SEG(SS), regs), 0); +} + // Unsupported static void handle_1aXX(struct bregs *regs) @@ -260,17 +272,15 @@ handle_1a(struct bregs *regs) case 0x05: handle_1a05(regs); break; case 0x06: handle_1a06(regs); break; case 0x07: handle_1a07(regs); break; + case 0xbb: handle_1abb(regs); break; default: handle_1aXX(regs); break; } } -// INT 08h System Timer ISR Entry Point -void VISIBLE16 -handle_08(void) +// Update main tick counter +static void +clock_update(void) { - debug_isr(DEBUG_ISR_08); - - // Update counter u32 counter = GET_BDA(timer_counter); counter++; // compare to one days worth of timer ticks at 18.2 hz @@ -284,6 +294,15 @@ handle_08(void) // Check for internal events. floppy_tick(); usb_check_event(); + ps2_check_event(); +} + +// INT 08h System Timer ISR Entry Point +void VISIBLE16 +handle_08(void) +{ + debug_isr(DEBUG_ISR_08); + clock_update(); // chain to user timer tick INT #0x1c struct bregs br; @@ -294,6 +313,20 @@ handle_08(void) pic_eoi1(); } +u32 last_timer_check VARLOW; + +// Simulate timer irq on machines without hardware irqs +void +clock_poll_irq(void) +{ + if (CONFIG_HARDWARE_IRQ) + return; + if (!timer_check(GET_LOW(last_timer_check))) + return; + SET_LOW(last_timer_check, timer_calc(ticks_to_ms(1))); + clock_update(); +} + /**************************************************************** * IRQ based timer @@ -359,6 +392,10 @@ clear_usertimer(void) void handle_1586(struct bregs *regs) { + if (!CONFIG_RTC_TIMER) { + set_code_unimplemented(regs, RET_EUNSUPPORTED); + return; + } // Use the rtc to wait for the specified time. u8 statusflag = 0; u32 count = (regs->cx << 16) | regs->dx; @@ -402,6 +439,10 @@ handle_1583XX(struct bregs *regs) void handle_1583(struct bregs *regs) { + if (!CONFIG_RTC_TIMER) { + handle_1583XX(regs); + return; + } switch (regs->al) { case 0x00: handle_158300(regs); break; case 0x01: handle_158301(regs); break; @@ -415,6 +456,8 @@ handle_1583(struct bregs *regs) void VISIBLE16 handle_70(void) { + if (!CONFIG_RTC_TIMER) + return; debug_isr(DEBUG_ISR_70); // Check which modes are enabled and have occurred. diff --git a/roms/seabios/src/config.h b/roms/seabios/src/config.h index 6da067d0b..6c47f161c 100644 --- a/roms/seabios/src/config.h +++ b/roms/seabios/src/config.h @@ -22,6 +22,8 @@ #define BUILD_MAX_EXTDRIVE 16 // Number of bytes the smbios may be and still live in the f-segment #define BUILD_MAX_SMBIOS_FSEG 600 +// Maximum number of bytes the mptable may be and still be copied to f-segment +#define BUILD_MAX_MPTABLE_FSEG 600 #define BUILD_MODEL_ID 0xFC #define BUILD_SUBMODEL_ID 0x00 @@ -104,5 +106,6 @@ #define DEBUG_unimplemented 2 #define DEBUG_invalid 3 #define DEBUG_thread 2 +#define DEBUG_tcg 20 #endif // config.h diff --git a/roms/seabios/src/disk.c b/roms/seabios/src/disk.c index 0e0af24b3..3854d0024 100644 --- a/roms/seabios/src/disk.c +++ b/roms/seabios/src/disk.c @@ -407,6 +407,9 @@ disk_1344(struct bregs *regs, struct drive_s *drive_gf) extended_access(regs, drive_gf, CMD_VERIFY); } +// Locks for removable devices +u8 CDRom_locks[BUILD_MAX_EXTDRIVE] VARLOW; + // lock static void disk_134500(struct bregs *regs, struct drive_s *drive_gf) @@ -519,7 +522,7 @@ disk_1347(struct bregs *regs, struct drive_s *drive_gf) static void disk_1348(struct bregs *regs, struct drive_s *drive_gf) { - int ret = fill_edd(regs->ds, (void*)(regs->si+0), drive_gf); + int ret = fill_edd(SEGOFF(regs->ds, regs->si), drive_gf); disk_ret(regs, ret); } diff --git a/roms/seabios/src/memmap.c b/roms/seabios/src/e820map.c index e03f8d0bf..39445cf63 100644 --- a/roms/seabios/src/memmap.c +++ b/roms/seabios/src/e820map.c @@ -5,7 +5,7 @@ // This file may be distributed under the terms of the GNU LGPLv3 license. #include "config.h" // BUILD_MAX_E820 -#include "memmap.h" // struct e820entry +#include "e820map.h" // struct e820entry #include "output.h" // dprintf #include "string.h" // memmove @@ -54,7 +54,6 @@ e820_type_name(u32 type) case E820_ACPI: return "ACPI"; case E820_NVS: return "NVS"; case E820_UNUSABLE: return "UNUSABLE"; - case E820_HOLE: return "HOLE"; default: return "UNKNOWN"; } } @@ -73,12 +72,14 @@ dump_map(void) } } +#define E820_HOLE ((u32)-1) // Used internally to remove entries + // Add a new entry to the list. This scans for overlaps and keeps the // list sorted. void -add_e820(u64 start, u64 size, u32 type) +e820_add(u64 start, u64 size, u32 type) { - dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type); + dprintf(8, "Add to e820 map: %08llx %08llx %d\n", start, size, type); if (! size) // Huh? Nothing to do. @@ -136,9 +137,16 @@ add_e820(u64 start, u64 size, u32 type) //dump_map(); } +// Remove any definitions in a memory range (make a memory hole). +void +e820_remove(u64 start, u64 size) +{ + e820_add(start, size, E820_HOLE); +} + // Report on final memory locations. void -memmap_prepboot(void) +e820_prepboot(void) { dump_map(); } diff --git a/roms/seabios/src/e820map.h b/roms/seabios/src/e820map.h new file mode 100644 index 000000000..de8b52300 --- /dev/null +++ b/roms/seabios/src/e820map.h @@ -0,0 +1,26 @@ +#ifndef __E820MAP_H +#define __E820MAP_H + +#include "types.h" // u64 + +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 +#define E820_UNUSABLE 5 + +struct e820entry { + u64 start; + u64 size; + u32 type; +}; + +void e820_add(u64 start, u64 size, u32 type); +void e820_remove(u64 start, u64 size); +void e820_prepboot(void); + +// e820 map storage +extern struct e820entry e820_list[]; +extern int e820_count; + +#endif // e820map.h diff --git a/roms/seabios/src/fw/biostables.c b/roms/seabios/src/fw/biostables.c index 50a891be8..9fb9ff9df 100644 --- a/roms/seabios/src/fw/biostables.c +++ b/roms/seabios/src/fw/biostables.c @@ -6,14 +6,15 @@ #include "byteorder.h" // le32_to_cpu #include "config.h" // CONFIG_* +#include "hw/pci.h" // pci_config_writeb #include "malloc.h" // malloc_fseg +#include "memmap.h" // SYMBOL #include "output.h" // dprintf -#include "hw/pci.h" // pci_config_writeb +#include "romfile.h" // romfile_find #include "std/acpi.h" // struct rsdp_descriptor #include "std/mptable.h" // MPTABLE_SIGNATURE #include "std/pirtable.h" // struct pir_header #include "std/smbios.h" // struct smbios_entry_point -#include "romfile.h" #include "string.h" // memcpy #include "util.h" // copy_table #include "x86.h" // outb @@ -54,6 +55,11 @@ copy_mptable(void *pos) return; u32 length = p->length * 16; u16 mpclength = ((struct mptable_config_s *)p->physaddr)->length; + if (length + mpclength > BUILD_MAX_MPTABLE_FSEG) { + dprintf(1, "Skipping MPTABLE copy due to large size (%d bytes)\n" + , length + mpclength); + return; + } // Allocate final memory location. (In theory the config // structure can go in high memory, but Linux kernels before // v2.6.30 crash with that.) @@ -117,9 +123,8 @@ copy_acpi_rsdp(void *pos) void *find_acpi_rsdp(void) { - extern u8 zonefseg_start[], zonefseg_end[]; - unsigned long start = (unsigned long)zonefseg_start; - unsigned long end = (unsigned long)zonefseg_end; + unsigned long start = SYMBOL(zonefseg_start); + unsigned long end = SYMBOL(zonefseg_end); unsigned long pos; for (pos = ALIGN(start, 0x10); pos <= ALIGN_DOWN(end, 0x10); pos += 0x10) @@ -271,7 +276,7 @@ copy_smbios(void *pos) if (SMBiosAddr) return; struct smbios_entry_point *p = pos; - if (memcmp(p->anchor_string, "_SM_", 4)) + if (p->signature != SMBIOS_SIGNATURE) return; if (checksum(pos, 0x10) != 0) return; @@ -301,17 +306,42 @@ display_uuid(void) if (memcmp(uuid, empty_uuid, sizeof(empty_uuid)) == 0) return; - printf("Machine UUID" - " %02x%02x%02x%02x" - "-%02x%02x" - "-%02x%02x" - "-%02x%02x" - "-%02x%02x%02x%02x%02x%02x\n" - , uuid[ 0], uuid[ 1], uuid[ 2], uuid[ 3] - , uuid[ 4], uuid[ 5] - , uuid[ 6], uuid[ 7] - , uuid[ 8], uuid[ 9] - , uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]); + /* + * According to SMBIOS v2.6 the first three fields are encoded in + * little-endian format. Versions prior to v2.6 did not specify + * the encoding, but we follow dmidecode and assume big-endian + * encoding. + */ + if (SMBiosAddr->smbios_major_version > 2 || + (SMBiosAddr->smbios_major_version == 2 && + SMBiosAddr->smbios_minor_version >= 6)) { + printf("Machine UUID" + " %02x%02x%02x%02x" + "-%02x%02x" + "-%02x%02x" + "-%02x%02x" + "-%02x%02x%02x%02x%02x%02x\n" + , uuid[ 3], uuid[ 2], uuid[ 1], uuid[ 0] + , uuid[ 5], uuid[ 4] + , uuid[ 7], uuid[ 6] + , uuid[ 8], uuid[ 9] + , uuid[10], uuid[11], uuid[12] + , uuid[13], uuid[14], uuid[15]); + } else { + printf("Machine UUID" + " %02x%02x%02x%02x" + "-%02x%02x" + "-%02x%02x" + "-%02x%02x" + "-%02x%02x%02x%02x%02x%02x\n" + , uuid[ 0], uuid[ 1], uuid[ 2], uuid[ 3] + , uuid[ 4], uuid[ 5] + , uuid[ 6], uuid[ 7] + , uuid[ 8], uuid[ 9] + , uuid[10], uuid[11], uuid[12] + , uuid[13], uuid[14], uuid[15]); + } + return; } } @@ -447,7 +477,7 @@ void smbios_setup(void) { if (smbios_romfile_setup()) - return; + return; smbios_legacy_setup(); } diff --git a/roms/seabios/src/fw/coreboot.c b/roms/seabios/src/fw/coreboot.c index 8fd84493b..4fe12928c 100644 --- a/roms/seabios/src/fw/coreboot.c +++ b/roms/seabios/src/fw/coreboot.c @@ -7,10 +7,10 @@ #include "block.h" // MAXDESCSIZE #include "byteorder.h" // be32_to_cpu #include "config.h" // CONFIG_* +#include "e820map.h" // e820_add #include "hw/pci.h" // pci_probe_devices #include "lzmadecode.h" // LzmaDecode #include "malloc.h" // free -#include "memmap.h" // add_e820 #include "output.h" // dprintf #include "paravirt.h" // PlatformRunningOn #include "romfile.h" // romfile_findprefix @@ -184,12 +184,12 @@ coreboot_preinit(void) u32 type = m->type; if (type == CB_MEM_TABLE) type = E820_RESERVED; - add_e820(m->start, m->size, type); + e820_add(m->start, m->size, type); } // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this // confuses grub. So, override it. - add_e820(0, 16*1024, E820_RAM); + e820_add(0, 16*1024, E820_RAM); struct cb_cbmem_ref *cbref = find_cb_subtable(cbh, CB_TAG_CBMEM_CONSOLE); if (cbref) { @@ -210,7 +210,7 @@ coreboot_preinit(void) fail: // No table found.. Use 16Megs as a dummy value. dprintf(1, "Unable to find coreboot table!\n"); - add_e820(0, 16*1024*1024, E820_RAM); + e820_add(0, 16*1024*1024, E820_RAM); return; } @@ -421,6 +421,13 @@ coreboot_cbfs_init(void) return; struct cbfs_header *hdr = *(void **)(CONFIG_CBFS_LOCATION - 4); + if ((u32)hdr & 0x03) { + dprintf(1, "Invalid CBFS pointer %p\n", hdr); + return; + } + if (CONFIG_CBFS_LOCATION && (u32)hdr > CONFIG_CBFS_LOCATION) + // Looks like the pointer is relative to CONFIG_CBFS_LOCATION + hdr = (void*)hdr + CONFIG_CBFS_LOCATION; if (hdr->magic != cpu_to_be32(CBFS_HEADER_MAGIC)) { dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n" , hdr, hdr->magic, cpu_to_be32(CBFS_HEADER_MAGIC)); @@ -503,7 +510,7 @@ cbfs_run_payload(struct cbfs_file *fhdr) break; case PAYLOAD_SEGMENT_ENTRY: { dprintf(1, "Calling addr %p\n", dest); - void (*func)() = dest; + void (*func)(void) = dest; func(); return; } diff --git a/roms/seabios/src/fw/csm.c b/roms/seabios/src/fw/csm.c index 7cdb398f2..7cadd12e5 100644 --- a/roms/seabios/src/fw/csm.c +++ b/roms/seabios/src/fw/csm.c @@ -4,20 +4,21 @@ // // This file may be distributed under the terms of the GNU LGPLv3 license. -#include "bregs.h" +#include "bregs.h" // struct bregs #include "config.h" // CONFIG_* +#include "e820map.h" // e820_add #include "farptr.h" // MAKE_FLATPTR -#include "hw/pci.h" -#include "hw/pic.h" -#include "malloc.h" // csm_malloc_preinit -#include "memmap.h" +#include "hw/pci.h" // pci_probe_devices +#include "hw/pic.h" // pic_irqmask_read +#include "malloc.h" // malloc_csm_preinit +#include "memmap.h" // SYMBOL #include "output.h" // dprintf +#include "paravirt.h" // qemu_preinit #include "stacks.h" // wait_threads #include "std/acpi.h" // RSDP_SIGNATURE #include "std/bda.h" // struct bios_data_area_s #include "std/optionrom.h" // struct rom_header #include "util.h" // copy_smbios -#include "paravirt.h" // qemu_preinit #define UINT8 u8 #define UINT16 u16 @@ -47,12 +48,11 @@ static void csm_return(struct bregs *regs) { u32 rommax = rom_get_max(); - extern u8 final_readonly_start[]; dprintf(3, "handle_csm returning AX=%04x\n", regs->ax); csm_compat_table.UmaAddress = rommax; - csm_compat_table.UmaSize = (u32)final_readonly_start - rommax; + csm_compat_table.UmaSize = SYMBOL(final_readonly_start) - rommax; PICMask = pic_irqmask_read(); __csm_return(regs); @@ -95,7 +95,7 @@ handle_csm_0000(struct bregs *regs) dprintf(3, "LoPmmMemory %08x\n", csm_init_table->LowPmmMemory); dprintf(3, "LoPmmMemorySize %08x\n", csm_init_table->LowPmmMemorySizeInBytes); - csm_malloc_preinit(csm_init_table->LowPmmMemory, + malloc_csm_preinit(csm_init_table->LowPmmMemory, csm_init_table->LowPmmMemorySizeInBytes, csm_init_table->HiPmmMemory, csm_init_table->HiPmmMemorySizeInBytes); @@ -147,11 +147,11 @@ handle_csm_0002(struct bregs *regs) struct e820entry *p = (void *)csm_compat_table.E820Pointer; int i; for (i=0; i < csm_compat_table.E820Length / sizeof(struct e820entry); i++) - add_e820(p[i].start, p[i].size, p[i].type); + e820_add(p[i].start, p[i].size, p[i].type); if (csm_init_table->HiPmmMemorySizeInBytes > BUILD_MAX_HIGHTABLE) { u32 hi_pmm_end = csm_init_table->HiPmmMemory + csm_init_table->HiPmmMemorySizeInBytes; - add_e820(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED); + e820_add(hi_pmm_end - BUILD_MAX_HIGHTABLE, BUILD_MAX_HIGHTABLE, E820_RESERVED); } // For PCIBIOS 1ab10e @@ -183,6 +183,7 @@ handle_csm_0002(struct bregs *regs) struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0); bda->hdcount = 0; + thread_setup(); mathcp_setup(); timer_setup(); clock_setup(); diff --git a/roms/seabios/src/fw/dev-q35.h b/roms/seabios/src/fw/dev-q35.h index c6f8bd9e7..201825deb 100644 --- a/roms/seabios/src/fw/dev-q35.h +++ b/roms/seabios/src/fw/dev-q35.h @@ -27,6 +27,9 @@ #define ICH9_LPC_GEN_PMCON_1_SMI_LOCK (1 << 4) #define ICH9_LPC_PORT_ELCR1 0x4d0 #define ICH9_LPC_PORT_ELCR2 0x4d1 +#define ICH9_LPC_RCBA 0xf0 +#define ICH9_LPC_RCBA_ADDR 0xfed1c000 +#define ICH9_LPC_RCBA_EN 0x1 #define PCI_DEVICE_ID_INTEL_ICH9_SMBUS 0x2930 #define ICH9_SMB_SMB_BASE 0x20 #define ICH9_SMB_HOSTC 0x40 diff --git a/roms/seabios/src/fw/multiboot.c b/roms/seabios/src/fw/multiboot.c new file mode 100644 index 000000000..d9df06764 --- /dev/null +++ b/roms/seabios/src/fw/multiboot.c @@ -0,0 +1,111 @@ +// Multiboot interface support. +// +// Copyright (C) 2015 Vladimir Serbinenko <phcoder@gmail.com> +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "config.h" // CONFIG_* +#include "malloc.h" // free +#include "output.h" // dprintf +#include "romfile.h" // romfile_add +#include "std/multiboot.h" // MULTIBOOT_* +#include "string.h" // memset +#include "util.h" // multiboot_init + +struct mbfs_romfile_s { + struct romfile_s file; + void *data; +}; + +static int +extract_filename(char *dest, char *src, size_t lim) +{ + char *ptr; + for (ptr = src; *ptr; ptr++) { + if (!(ptr == src || ptr[-1] == ' ' || ptr[-1] == '\t')) + continue; + /* memcmp stops early if it encounters \0 as it doesn't match name=. */ + if (memcmp(ptr, "name=", 5) == 0) { + int i; + char *optr = dest; + for (i = 0, ptr += 5; *ptr && *ptr != ' ' && i < lim; i++) { + *optr++ = *ptr++; + } + *optr++ = '\0'; + return 1; + } + } + return 0; +} + +// Copy a file to memory +static int +mbfs_copyfile(struct romfile_s *file, void *dst, u32 maxlen) +{ + struct mbfs_romfile_s *cfile; + cfile = container_of(file, struct mbfs_romfile_s, file); + u32 size = cfile->file.size; + void *src = cfile->data; + + // Not compressed. + dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst); + if (size > maxlen) { + warn_noalloc(); + return -1; + } + iomemcpy(dst, src, size); + return size; +} + +u32 __VISIBLE entry_elf_eax, entry_elf_ebx; + +void +multiboot_init(void) +{ + struct multiboot_info *mbi; + if (!CONFIG_MULTIBOOT) + return; + dprintf(1, "multiboot: eax=%x, ebx=%x\n", entry_elf_eax, entry_elf_ebx); + if (entry_elf_eax != MULTIBOOT_BOOTLOADER_MAGIC) + return; + mbi = (void *)entry_elf_ebx; + dprintf(1, "mbptr=%p\n", mbi); + dprintf(1, "flags=0x%x, mods=0x%x, mods_c=%d\n", mbi->flags, mbi->mods_addr, + mbi->mods_count); + if (!(mbi->flags & MULTIBOOT_INFO_MODS)) + return; + int i; + struct multiboot_mod_list *mod = (void *)mbi->mods_addr; + for (i = 0; i < mbi->mods_count; i++) { + struct mbfs_romfile_s *cfile; + u8 *copy; + u32 len; + if (!mod[i].cmdline) + continue; + len = mod[i].mod_end - mod[i].mod_start; + cfile = malloc_tmp(sizeof(*cfile)); + if (!cfile) { + warn_noalloc(); + return; + } + memset(cfile, 0, sizeof(*cfile)); + dprintf(1, "module %s, size 0x%x\n", (char *)mod[i].cmdline, len); + if (!extract_filename(cfile->file.name, (char *)mod[i].cmdline, + sizeof(cfile->file.name))) { + free(cfile); + continue; + } + dprintf(1, "assigned file name <%s>\n", cfile->file.name); + cfile->file.size = len; + copy = malloc_tmp(len); + if (!copy) { + warn_noalloc(); + free(cfile); + return; + } + memcpy(copy, (void *)mod[i].mod_start, len); + cfile->file.copy = mbfs_copyfile; + cfile->data = copy; + romfile_add(&cfile->file); + } +} diff --git a/roms/seabios/src/fw/paravirt.c b/roms/seabios/src/fw/paravirt.c index db22ae8fc..3fae13a83 100644 --- a/roms/seabios/src/fw/paravirt.c +++ b/roms/seabios/src/fw/paravirt.c @@ -10,11 +10,11 @@ #include "byteorder.h" // be32_to_cpu #include "config.h" // CONFIG_QEMU +#include "e820map.h" // e820_add #include "hw/pci.h" // create_pirtable #include "hw/pci_regs.h" // PCI_DEVICE_ID #include "hw/rtc.h" // CMOS_* #include "malloc.h" // malloc_tmp -#include "memmap.h" // add_e820 #include "output.h" // dprintf #include "paravirt.h" // qemu_cfg_preinit #include "romfile.h" // romfile_loadint @@ -23,6 +23,7 @@ #include "util.h" // pci_setup #include "x86.h" // cpuid #include "xen.h" // xen_biostable_setup +#include "stacks.h" // yield // Amount of continuous ram under 4Gig u32 RamSize; @@ -30,6 +31,13 @@ u32 RamSize; u64 RamSizeOver4G; // Type of emulator platform. int PlatformRunningOn VARFSEG; +// cfg_dma enabled +int cfg_dma_enabled = 0; + +inline int qemu_cfg_dma_enabled(void) +{ + return cfg_dma_enabled; +} /* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It * should be used to determine that a VM is running under KVM. @@ -114,10 +122,10 @@ qemu_preinit(void) | (rtc_read(CMOS_MEM_EXTMEM_HIGH) << 18)) + 1 * 1024 * 1024); RamSize = rs; - add_e820(0, rs, E820_RAM); + e820_add(0, rs, E820_RAM); /* reserve 256KB BIOS area at the end of 4 GB */ - add_e820(0xfffc0000, 256*1024, E820_RESERVED); + e820_add(0xfffc0000, 256*1024, E820_RESERVED); dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize); } @@ -199,23 +207,63 @@ qemu_cfg_select(u16 f) } static void +qemu_cfg_dma_transfer(void *address, u32 length, u32 control) +{ + QemuCfgDmaAccess access; + + access.address = cpu_to_be64((u64)(u32)address); + access.length = cpu_to_be32(length); + access.control = cpu_to_be32(control); + + barrier(); + + outl(cpu_to_be32((u32)&access), PORT_QEMU_CFG_DMA_ADDR_LOW); + + while(be32_to_cpu(access.control) & ~QEMU_CFG_DMA_CTL_ERROR) { + yield(); + } +} + +static void qemu_cfg_read(void *buf, int len) { - insb(PORT_QEMU_CFG_DATA, buf, len); + if (len == 0) { + return; + } + + if (qemu_cfg_dma_enabled()) { + qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_READ); + } else { + insb(PORT_QEMU_CFG_DATA, buf, len); + } } static void qemu_cfg_skip(int len) { - while (len--) - inb(PORT_QEMU_CFG_DATA); + if (len == 0) { + return; + } + + if (qemu_cfg_dma_enabled()) { + qemu_cfg_dma_transfer(0, len, QEMU_CFG_DMA_CTL_SKIP); + } else { + while (len--) + inb(PORT_QEMU_CFG_DATA); + } } static void qemu_cfg_read_entry(void *buf, int e, int len) { - qemu_cfg_select(e); - qemu_cfg_read(buf, len); + if (qemu_cfg_dma_enabled()) { + u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT + | QEMU_CFG_DMA_CTL_READ; + qemu_cfg_dma_transfer(buf, len, control); + } else { + qemu_cfg_select(e); + qemu_cfg_read(buf, len); + } } struct qemu_romfile_s { @@ -230,9 +278,14 @@ qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen) return -1; struct qemu_romfile_s *qfile; qfile = container_of(file, struct qemu_romfile_s, file); - qemu_cfg_select(qfile->select); - qemu_cfg_skip(qfile->skip); - qemu_cfg_read(dst, file->size); + if (qfile->skip == 0) { + /* Do it in one transfer */ + qemu_cfg_read_entry(dst, qfile->select, file->size); + } else { + qemu_cfg_select(qfile->select); + qemu_cfg_skip(qfile->skip); + qemu_cfg_read(dst, file->size); + } return file->size; } @@ -302,7 +355,7 @@ qemu_cfg_e820(void) } /* fall through */ case E820_RESERVED: - add_e820(table[i].address, table[i].length, table[i].type); + e820_add(table[i].address, table[i].length, table[i].type); break; default: /* @@ -324,13 +377,13 @@ qemu_cfg_e820(void) int i; for (i = 0; i < count32; i++) { qemu_cfg_read(&entry, sizeof(entry)); - add_e820(entry.address, entry.length, entry.type); + e820_add(entry.address, entry.length, entry.type); } } else if (runningOnKVM()) { // Backwards compatibility - provide hard coded range. // 4 pages before the bios, 3 pages for vmx tss pages, the // other page for EPT real mode pagetable - add_e820(0xfffbc000, 4*4096, E820_RESERVED); + e820_add(0xfffbc000, 4*4096, E820_RESERVED); } // Check for memory over 4Gig in cmos @@ -338,7 +391,7 @@ qemu_cfg_e820(void) | ((u32)rtc_read(CMOS_MEM_HIGHMEM_MID) << 24) | ((u64)rtc_read(CMOS_MEM_HIGHMEM_HIGH) << 32)); RamSizeOver4G = high; - add_e820(0x100000000ull, high, E820_RAM); + e820_add(0x100000000ull, high, E820_RAM); dprintf(1, "RamSizeOver4G: 0x%016llx [cmos]\n", RamSizeOver4G); } @@ -422,8 +475,18 @@ void qemu_cfg_init(void) for (i = 0; i < 4; i++) if (inb(PORT_QEMU_CFG_DATA) != sig[i]) return; + dprintf(1, "Found QEMU fw_cfg\n"); + // Detect DMA interface. + u32 id; + qemu_cfg_read_entry(&id, QEMU_CFG_ID, sizeof(id)); + + if (id & QEMU_CFG_VERSION_DMA) { + dprintf(1, "QEMU fw_cfg DMA interface supported\n"); + cfg_dma_enabled = 1; + } + // Populate romfiles for legacy fw_cfg entries qemu_cfg_legacy(); diff --git a/roms/seabios/src/fw/paravirt.h b/roms/seabios/src/fw/paravirt.h index 95ffb92ad..ed8e5f1f8 100644 --- a/roms/seabios/src/fw/paravirt.h +++ b/roms/seabios/src/fw/paravirt.h @@ -9,6 +9,12 @@ #define PF_XEN (1<<1) #define PF_KVM (1<<2) +typedef struct QemuCfgDmaAccess { + u32 control; + u32 length; + u64 address; +} PACKED QemuCfgDmaAccess; + extern u32 RamSize; extern u64 RamSizeOver4G; extern int PlatformRunningOn; @@ -25,11 +31,23 @@ static inline int runningOnKVM(void) { } // Common paravirt ports. -#define PORT_SMI_CMD 0x00b2 -#define PORT_SMI_STATUS 0x00b3 -#define PORT_QEMU_CFG_CTL 0x0510 -#define PORT_QEMU_CFG_DATA 0x0511 +#define PORT_SMI_CMD 0x00b2 +#define PORT_SMI_STATUS 0x00b3 +#define PORT_QEMU_CFG_CTL 0x0510 +#define PORT_QEMU_CFG_DATA 0x0511 +#define PORT_QEMU_CFG_DMA_ADDR_HIGH 0x0514 +#define PORT_QEMU_CFG_DMA_ADDR_LOW 0x0518 + +// QEMU_CFG_DMA_CONTROL bits +#define QEMU_CFG_DMA_CTL_ERROR 0x01 +#define QEMU_CFG_DMA_CTL_READ 0x02 +#define QEMU_CFG_DMA_CTL_SKIP 0x04 +#define QEMU_CFG_DMA_CTL_SELECT 0x08 + +// QEMU_CFG_DMA ID bit +#define QEMU_CFG_VERSION_DMA 2 +int qemu_cfg_dma_enabled(void); void qemu_preinit(void); void qemu_platform_setup(void); void qemu_cfg_init(void); diff --git a/roms/seabios/src/fw/pciinit.c b/roms/seabios/src/fw/pciinit.c index 46ae7090e..c31c2fa0c 100644 --- a/roms/seabios/src/fw/pciinit.c +++ b/roms/seabios/src/fw/pciinit.c @@ -9,13 +9,13 @@ #include "config.h" // CONFIG_* #include "dev-q35.h" // Q35_HOST_BRIDGE_PCIEXBAR_ADDR #include "dev-piix.h" // PIIX_* +#include "e820map.h" // e820_add #include "hw/ata.h" // PORT_ATA1_CMD_BASE #include "hw/pci.h" // pci_config_readl #include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL #include "hw/pci_regs.h" // PCI_COMMAND #include "list.h" // struct hlist_node #include "malloc.h" // free -#include "memmap.h" // add_e820 #include "output.h" // dprintf #include "paravirt.h" // RamSize #include "romfile.h" // romfile_loadint @@ -183,6 +183,11 @@ static void mch_isa_bridge_setup(struct pci_device *dev, void *arg) /* acpi enable, SCI: IRQ9 000b = irq9*/ pci_config_writeb(bdf, ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_ACPI_EN); + /* set root complex register block BAR */ + pci_config_writel(bdf, ICH9_LPC_RCBA, + ICH9_LPC_RCBA_ADDR | ICH9_LPC_RCBA_EN); + e820_add(ICH9_LPC_RCBA_ADDR, 16*1024, E820_RESERVED); + acpi_pm1a_cnt = acpi_pm_base + 0x04; pmtimer_setup(acpi_pm_base + 0x08); } @@ -316,6 +321,10 @@ static void pci_bios_init_device(struct pci_device *pci) /* enable memory mappings */ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SERR); + /* enable SERR# for forwarding */ + if (pci->header_type & PCI_HEADER_TYPE_BRIDGE) + pci_config_maskw(bdf, PCI_BRIDGE_CONTROL, 0, + PCI_BRIDGE_CTL_SERR); } static void pci_bios_init_devices(void) @@ -391,7 +400,7 @@ static void mch_mem_addr_setup(struct pci_device *dev, void *arg) pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, 0); pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR + 4, upper); pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower); - add_e820(addr, size, E820_RESERVED); + e820_add(addr, size, E820_RESERVED); /* setup pci i/o window (above mmconfig) */ pcimem_start = addr + size; @@ -636,9 +645,8 @@ pci_region_create_entry(struct pci_bus *bus, struct pci_device *dev, return entry; } -static int pci_bus_hotplug_support(struct pci_bus *bus) +static int pci_bus_hotplug_support(struct pci_bus *bus, u8 pcie_cap) { - u8 pcie_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_EXP); u8 shpc_cap; if (pcie_cap) { @@ -662,7 +670,7 @@ static int pci_bus_hotplug_support(struct pci_bus *bus) return downstream_port && slot_implemented; } - shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC); + shpc_cap = pci_find_capability(bus->bus_dev, PCI_CAP_ID_SHPC, 0); return !!shpc_cap; } @@ -718,7 +726,8 @@ static int pci_bios_check_devices(struct pci_bus *busses) */ parent = &busses[0]; int type; - int hotplug_support = pci_bus_hotplug_support(s); + u8 pcie_cap = pci_find_capability(s->bus_dev, PCI_CAP_ID_EXP, 0); + int hotplug_support = pci_bus_hotplug_support(s, pcie_cap); for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) { u64 align = (type == PCI_REGION_TYPE_IO) ? PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN; @@ -727,7 +736,8 @@ static int pci_bios_check_devices(struct pci_bus *busses) if (pci_region_align(&s->r[type]) > align) align = pci_region_align(&s->r[type]); u64 sum = pci_region_sum(&s->r[type]); - if (!sum && hotplug_support) + int resource_optional = pcie_cap && (type == PCI_REGION_TYPE_IO); + if (!sum && hotplug_support && !resource_optional) sum = align; /* reserve min size for hot-plug */ u64 size = ALIGN(sum, align); int is64 = pci_bios_bridge_region_is64(&s->r[type], diff --git a/roms/seabios/src/fw/shadow.c b/roms/seabios/src/fw/shadow.c index 4f00006bf..ee87d36e0 100644 --- a/roms/seabios/src/fw/shadow.c +++ b/roms/seabios/src/fw/shadow.c @@ -53,9 +53,8 @@ __make_bios_writable_intel(u16 bdf, u32 pam0) return; // Copy bios. - extern u8 code32flat_start[], code32flat_end[]; - memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET - , code32flat_end - code32flat_start); + memcpy(VSYMBOL(code32flat_start), VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET + , SYMBOL(code32flat_end) - SYMBOL(code32flat_start)); } static void @@ -65,7 +64,7 @@ make_bios_writable_intel(u16 bdf, u32 pam0) if (!(reg & 0x10)) { // QEMU doesn't fully implement the piix shadow capabilities - // if ram isn't backing the bios segment when shadowing is - // disabled, the code itself wont be in memory. So, run the + // disabled, the code itself won't be in memory. So, run the // code from the high-memory flash location. u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET; void (*func)(u16 bdf, u32 pam0) = (void*)pos; @@ -165,7 +164,6 @@ qemu_prep_reset(void) // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a // reset, so do that manually before invoking a hard reset. make_bios_writable(); - extern u8 code32flat_start[], code32flat_end[]; - memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET - , code32flat_end - code32flat_start); + memcpy(VSYMBOL(code32flat_start), VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET + , SYMBOL(code32flat_end) - SYMBOL(code32flat_start)); } diff --git a/roms/seabios/src/fw/smbios.c b/roms/seabios/src/fw/smbios.c index dba054133..f3b5ad9dd 100644 --- a/roms/seabios/src/fw/smbios.c +++ b/roms/seabios/src/fw/smbios.c @@ -37,7 +37,7 @@ smbios_entry_point_setup(u16 max_structure_size, struct smbios_entry_point ep; memset(&ep, 0, sizeof(ep)); - memcpy(ep.anchor_string, "_SM_", 4); + ep.signature = SMBIOS_SIGNATURE; ep.length = 0x1f; ep.smbios_major_version = 2; ep.smbios_minor_version = 4; diff --git a/roms/seabios/src/fw/smm.c b/roms/seabios/src/fw/smm.c index 6cb484e7e..8f042ee4d 100644 --- a/roms/seabios/src/fw/smm.c +++ b/roms/seabios/src/fw/smm.c @@ -64,11 +64,11 @@ handle_smi(u16 cs) return; u8 cmd = inb(PORT_SMI_CMD); struct smm_layout *smm = MAKE_FLATPTR(cs, 0); + u32 rev = smm->cpu.i32.smm_rev & SMM_REV_MASK; dprintf(DEBUG_HDL_smi, "handle_smi cmd=%x smbase=%p\n", cmd, smm); if (smm == (void*)BUILD_SMM_INIT_ADDR) { // relocate SMBASE to 0xa0000 - u32 rev = smm->cpu.i32.smm_rev & SMM_REV_MASK; if (rev == SMM_REV_I32) { smm->cpu.i32.smm_base = BUILD_SMM_ADDR; } else if (rev == SMM_REV_I64) { @@ -92,7 +92,7 @@ handle_smi(u16 cs) } if (CONFIG_CALL32_SMM && cmd == CALL32SMM_CMDID) { - if (smm->cpu.i32.smm_rev == SMM_REV_I32) { + if (rev == SMM_REV_I32) { u32 regs[8]; memcpy(regs, &smm->cpu.i32.eax, sizeof(regs)); if (smm->cpu.i32.ecx == CALL32SMM_ENTERID) { @@ -107,7 +107,7 @@ handle_smi(u16 cs) memcpy(&smm->cpu.i32.eax, regs, sizeof(regs)); smm->cpu.i32.eip = regs[3]; } - } else if (smm->cpu.i64.smm_rev == SMM_REV_I64) { + } else if (rev == SMM_REV_I64) { u64 regs[8]; memcpy(regs, &smm->cpu.i64.rdi, sizeof(regs)); if ((u32)smm->cpu.i64.rcx == CALL32SMM_ENTERID) { @@ -184,7 +184,7 @@ static void piix4_apmc_smm_setup(int isabdf, int i440_bdf) /* enable SMI generation */ value = inl(acpi_pm_base + PIIX_PMIO_GLBCTL); - outl(acpi_pm_base + PIIX_PMIO_GLBCTL, value | PIIX_PMIO_GLBCTL_SMI_EN); + outl(value | PIIX_PMIO_GLBCTL_SMI_EN, acpi_pm_base + PIIX_PMIO_GLBCTL); smm_relocate_and_restore(); diff --git a/roms/seabios/src/fw/smp.c b/roms/seabios/src/fw/smp.c index a466ea6e9..579acdbd0 100644 --- a/roms/seabios/src/fw/smp.c +++ b/roms/seabios/src/fw/smp.c @@ -52,9 +52,6 @@ handle_smp(void) if (!CONFIG_QEMU) return; - // Enable CPU caching - setcr0(getcr0() & ~(CR0_CD|CR0_NW)); - // Detect apic_id u32 eax, ebx, ecx, cpuid_features; cpuid(1, &eax, &ebx, &ecx, &cpuid_features); diff --git a/roms/seabios/src/fw/xen.c b/roms/seabios/src/fw/xen.c index dd8e8afd4..3f19ef2dc 100644 --- a/roms/seabios/src/fw/xen.c +++ b/roms/seabios/src/fw/xen.c @@ -4,16 +4,17 @@ // // This file may be distributed under the terms of the GNU LGPLv3 license. -#include "config.h" +#include "config.h" // CONFIG_XEN +#include "e820map.h" // e820_add #include "hw/serialio.h" // DebugOutputPort #include "malloc.h" // memalign_high -#include "memmap.h" // add_e820 +#include "memmap.h" // PAGE_SIZE #include "output.h" // dprintf #include "paravirt.h" // PlatformRunningOn #include "string.h" // memcpy #include "util.h" // copy_acpi_rsdp #include "x86.h" // cpuid -#include "xen.h" +#include "xen.h" // xen_extraversion_t #define INFO_PHYSICAL_ADDRESS 0x00001000 @@ -142,6 +143,6 @@ void xen_ramsize_preinit(void) for (i = 0; i < info->e820_nr; i++) { struct e820entry *e = &e820[i]; - add_e820(e->start, e->size, e->type); + e820_add(e->start, e->size, e->type); } } diff --git a/roms/seabios/src/hw/ahci.c b/roms/seabios/src/hw/ahci.c index 3193d81a6..83b747cb2 100644 --- a/roms/seabios/src/hw/ahci.c +++ b/roms/seabios/src/hw/ahci.c @@ -213,7 +213,7 @@ static int ahci_command(struct ahci_port_s *port_gf, int iswrite, int isatapi, #define CDROM_CDB_SIZE 12 -int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +int ahci_atapi_process_op(struct disk_op_s *op) { if (! CONFIG_AHCI) return 0; @@ -221,15 +221,14 @@ int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) struct ahci_port_s *port_gf = container_of( op->drive_gf, struct ahci_port_s, drive); struct ahci_cmd_s *cmd = port_gf->cmd; - u8 *atapi = cdbcmd; - int i, rc; + if (op->command == CMD_WRITE || op->command == CMD_FORMAT) + return DISK_RET_EWRITEPROTECT; + int blocksize = scsi_fill_cmd(op, cmd->atapi, CDROM_CDB_SIZE); + if (blocksize < 0) + return default_process_op(op); sata_prep_atapi(&cmd->fis, blocksize); - for (i = 0; i < CDROM_CDB_SIZE; i++) { - cmd->atapi[i] = atapi[i]; - } - rc = ahci_command(port_gf, 0, 1, op->buf_fl, - op->count * blocksize); + int rc = ahci_command(port_gf, 0, 1, op->buf_fl, op->count * blocksize); if (rc < 0) return DISK_RET_EBADTRACK; return DISK_RET_SUCCESS; @@ -296,8 +295,8 @@ ahci_disk_readwrite(struct disk_op_s *op, int iswrite) } // command demuxer -int VISIBLE32FLAT -process_ahci_op(struct disk_op_s *op) +int +ahci_process_op(struct disk_op_s *op) { if (!CONFIG_AHCI) return 0; @@ -306,15 +305,8 @@ process_ahci_op(struct disk_op_s *op) return ahci_disk_readwrite(op, 0); case CMD_WRITE: return ahci_disk_readwrite(op, 1); - case CMD_FORMAT: - case CMD_RESET: - case CMD_ISREADY: - case CMD_VERIFY: - case CMD_SEEK: - return DISK_RET_SUCCESS; default: - dprintf(1, "AHCI: unknown disk command %d\n", op->command); - return DISK_RET_EPARAM; + return default_process_op(op); } } @@ -405,6 +397,14 @@ static struct ahci_port_s* ahci_port_realloc(struct ahci_port_s *port) port->list = memalign_high(1024, 1024); port->fis = memalign_high(256, 256); port->cmd = memalign_high(256, 256); + if (!port->list || !port->fis || !port->cmd) { + warn_noalloc(); + free(port->list); + free(port->fis); + free(port->cmd); + free(port); + return NULL; + } ahci_port_writel(port->ctrl, port->pnr, PORT_LST_ADDR, (u32)port->list); ahci_port_writel(port->ctrl, port->pnr, PORT_FIS_ADDR, (u32)port->fis); diff --git a/roms/seabios/src/hw/ahci.h b/roms/seabios/src/hw/ahci.h index c8c755a3f..fa11d6619 100644 --- a/roms/seabios/src/hw/ahci.h +++ b/roms/seabios/src/hw/ahci.h @@ -83,8 +83,8 @@ struct ahci_port_s { }; void ahci_setup(void); -int process_ahci_op(struct disk_op_s *op); -int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +int ahci_process_op(struct disk_op_s *op); +int ahci_atapi_process_op(struct disk_op_s *op); #define AHCI_IRQ_ON_SG (1 << 31) #define AHCI_CMD_ATAPI (1 << 5) diff --git a/roms/seabios/src/hw/ata.c b/roms/seabios/src/hw/ata.c index d805706dd..fbbbbc1bb 100644 --- a/roms/seabios/src/hw/ata.c +++ b/roms/seabios/src/hw/ata.c @@ -552,7 +552,7 @@ ata_readwrite(struct disk_op_s *op, int iswrite) // 16bit command demuxer for ATA harddrives. int -process_ata_op(struct disk_op_s *op) +ata_process_op(struct disk_op_s *op) { if (!CONFIG_ATA) return 0; @@ -569,12 +569,8 @@ process_ata_op(struct disk_op_s *op) return DISK_RET_SUCCESS; case CMD_ISREADY: return isready(adrive_gf); - case CMD_FORMAT: - case CMD_VERIFY: - case CMD_SEEK: - return DISK_RET_SUCCESS; default: - return DISK_RET_EPARAM; + return default_process_op(op); } } @@ -587,11 +583,18 @@ process_ata_op(struct disk_op_s *op) // Low-level atapi command transmit function. int -atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +ata_atapi_process_op(struct disk_op_s *op) { if (! CONFIG_ATA) return 0; + if (op->command == CMD_WRITE || op->command == CMD_FORMAT) + return DISK_RET_EWRITEPROTECT; + u8 cdbcmd[CDROM_CDB_SIZE]; + int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd)); + if (blocksize < 0) + return default_process_op(op); + struct atadrive_s *adrive_gf = container_of( op->drive_gf, struct atadrive_s, drive); struct ata_channel_s *chan_gf = GET_GLOBALFLAT(adrive_gf->chan_gf); @@ -715,7 +718,7 @@ init_atadrive(struct atadrive_s *dummy, u16 *buffer) memset(adrive, 0, sizeof(*adrive)); adrive->chan_gf = dummy->chan_gf; adrive->slave = dummy->slave; - adrive->drive.cntl_id = adrive->chan_gf->chanid * 2 + dummy->slave; + adrive->drive.cntl_id = adrive->chan_gf->ataid * 2 + dummy->slave; adrive->drive.removable = (buffer[0] & 0x80) ? 1 : 0; return adrive; } @@ -740,7 +743,7 @@ init_drive_atapi(struct atadrive_s *dummy, u16 *buffer) char model[MAXMODEL+1]; char *desc = znprintf(MAXDESCSIZE , "DVD/CD [ata%d-%d: %s ATAPI-%d %s]" - , adrive->chan_gf->chanid, adrive->slave + , adrive->chan_gf->ataid, adrive->slave , ata_extract_model(model, MAXMODEL, buffer) , ata_extract_version(buffer) , (iscd ? "DVD/CD" : "Device")); @@ -792,7 +795,7 @@ init_drive_ata(struct atadrive_s *dummy, u16 *buffer) char model[MAXMODEL+1]; char *desc = znprintf(MAXDESCSIZE , "ata%d-%d: %s ATA-%d Hard-Disk (%u %ciBytes)" - , adrive->chan_gf->chanid, adrive->slave + , adrive->chan_gf->ataid, adrive->slave , ata_extract_model(model, MAXMODEL, buffer) , ata_extract_version(buffer) , (u32)adjsize, adjprefix); @@ -866,7 +869,7 @@ ata_detect(void *data) u8 sc = inb(iobase1+ATA_CB_SC); u8 sn = inb(iobase1+ATA_CB_SN); dprintf(6, "ata_detect ata%d-%d: sc=%x sn=%x dh=%x\n" - , chan_gf->chanid, slave, sc, sn, dh); + , chan_gf->ataid, slave, sc, sn, dh); if (sc != 0x55 || sn != 0xaa || dh != newdh) continue; @@ -913,16 +916,17 @@ ata_detect(void *data) // Initialize an ata controller and detect its drives. static void -init_controller(struct pci_device *pci, int irq +init_controller(struct pci_device *pci, int chanid, int irq , u32 port1, u32 port2, u32 master) { - static int chanid = 0; + static int ataid = 0; struct ata_channel_s *chan_gf = malloc_fseg(sizeof(*chan_gf)); if (!chan_gf) { warn_noalloc(); return; } - chan_gf->chanid = chanid++; + chan_gf->ataid = ataid++; + chan_gf->chanid = chanid; chan_gf->irq = irq; chan_gf->pci_bdf = pci ? pci->bdf : -1; chan_gf->pci_tmp = pci; @@ -930,7 +934,7 @@ init_controller(struct pci_device *pci, int irq chan_gf->iobase2 = port2; chan_gf->iomaster = master; dprintf(1, "ATA controller %d at %x/%x/%x (irq %d dev %x)\n" - , chanid, port1, port2, master, irq, chan_gf->pci_bdf); + , ataid, port1, port2, master, irq, chan_gf->pci_bdf); run_thread(ata_detect, chan_gf); } @@ -966,7 +970,7 @@ init_pciata(struct pci_device *pci, u8 prog_if) port2 = PORT_ATA1_CTRL_BASE; irq = IRQ_ATA1; } - init_controller(pci, irq, port1, port2, master); + init_controller(pci, 0, irq, port1, port2, master); if (prog_if & 4) { port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2) @@ -979,7 +983,7 @@ init_pciata(struct pci_device *pci, u8 prog_if) port2 = PORT_ATA2_CTRL_BASE; irq = IRQ_ATA2; } - init_controller(pci, irq, port1, port2, master ? master + 8 : 0); + init_controller(pci, 1, irq, port1, port2, master ? master + 8 : 0); } static void @@ -1011,9 +1015,9 @@ ata_scan(void) if (CONFIG_QEMU && hlist_empty(&PCIDevices)) { // No PCI devices found - probably a QEMU "-M isapc" machine. // Try using ISA ports for ATA controllers. - init_controller(NULL, IRQ_ATA1 + init_controller(NULL, 0, IRQ_ATA1 , PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0); - init_controller(NULL, IRQ_ATA2 + init_controller(NULL, 1, IRQ_ATA2 , PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0); return; } diff --git a/roms/seabios/src/hw/ata.h b/roms/seabios/src/hw/ata.h index c73892bbe..cd14e59e9 100644 --- a/roms/seabios/src/hw/ata.h +++ b/roms/seabios/src/hw/ata.h @@ -11,6 +11,7 @@ struct ata_channel_s { u16 iomaster; u8 irq; u8 chanid; + u8 ataid; int pci_bdf; struct pci_device *pci_tmp; }; @@ -24,10 +25,9 @@ struct atadrive_s { // ata.c char *ata_extract_model(char *model, u32 size, u16 *buffer); int ata_extract_version(u16 *buffer); -int cdrom_read(struct disk_op_s *op); -int atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +int ata_process_op(struct disk_op_s *op); +int ata_atapi_process_op(struct disk_op_s *op); void ata_setup(void); -int process_ata_op(struct disk_op_s *op); #define PORT_ATA2_CMD_BASE 0x0170 #define PORT_ATA1_CMD_BASE 0x01f0 diff --git a/roms/seabios/src/hw/blockcmd.c b/roms/seabios/src/hw/blockcmd.c index 78c0e65f4..0725b46db 100644 --- a/roms/seabios/src/hw/blockcmd.c +++ b/roms/seabios/src/hw/blockcmd.c @@ -5,67 +5,14 @@ // // This file may be distributed under the terms of the GNU LGPLv3 license. -#include "ahci.h" // atapi_cmd_data -#include "ata.h" // atapi_cmd_data #include "biosvar.h" // GET_GLOBALFLAT #include "block.h" // struct disk_op_s #include "blockcmd.h" // struct cdb_request_sense #include "byteorder.h" // be32_to_cpu -#include "esp-scsi.h" // esp_scsi_cmd_data -#include "lsi-scsi.h" // lsi_scsi_cmd_data -#include "megasas.h" // megasas_cmd_data -#include "pvscsi.h" // pvscsi_cmd_data #include "output.h" // dprintf #include "std/disk.h" // DISK_RET_EPARAM #include "string.h" // memset -#include "usb-msc.h" // usb_cmd_data -#include "usb-uas.h" // usb_cmd_data #include "util.h" // timer_calc -#include "virtio-scsi.h" // virtio_scsi_cmd_data - -// Route command to low-level handler. -static int -cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) -{ - u8 type = GET_GLOBALFLAT(op->drive_gf->type); - switch (type) { - case DTYPE_ATA_ATAPI: - return atapi_cmd_data(op, cdbcmd, blocksize); - case DTYPE_USB: - return usb_cmd_data(op, cdbcmd, blocksize); - case DTYPE_UAS: - return uas_cmd_data(op, cdbcmd, blocksize); - case DTYPE_VIRTIO_SCSI: - return virtio_scsi_cmd_data(op, cdbcmd, blocksize); - case DTYPE_LSI_SCSI: - return lsi_scsi_cmd_data(op, cdbcmd, blocksize); - case DTYPE_ESP_SCSI: - return esp_scsi_cmd_data(op, cdbcmd, blocksize); - case DTYPE_MEGASAS: - return megasas_cmd_data(op, cdbcmd, blocksize); - case DTYPE_USB_32: - if (!MODESEGMENT) - return usb_cmd_data(op, cdbcmd, blocksize); - case DTYPE_UAS_32: - if (!MODESEGMENT) - return uas_cmd_data(op, cdbcmd, blocksize); - case DTYPE_PVSCSI: - if (!MODESEGMENT) - return pvscsi_cmd_data(op, cdbcmd, blocksize); - case DTYPE_AHCI_ATAPI: - if (!MODESEGMENT) - return ahci_cmd_data(op, cdbcmd, blocksize); - default: - return DISK_RET_EPARAM; - } -} - -// Determine if the command is a request to pull data from the device -int -cdb_is_read(u8 *cdbcmd, u16 blocksize) -{ - return blocksize && cdbcmd[0] != CDB_CMD_WRITE_10; -} /**************************************************************** @@ -79,9 +26,12 @@ cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data) memset(&cmd, 0, sizeof(cmd)); cmd.command = CDB_CMD_INQUIRY; cmd.length = sizeof(*data); + op->command = CMD_SCSI; op->count = 1; op->buf_fl = data; - return cdb_cmd_data(op, &cmd, sizeof(*data)); + op->cdbcmd = &cmd; + op->blocksize = sizeof(*data); + return process_op(op); } // Request SENSE @@ -92,9 +42,12 @@ cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data) memset(&cmd, 0, sizeof(cmd)); cmd.command = CDB_CMD_REQUEST_SENSE; cmd.length = sizeof(*data); + op->command = CMD_SCSI; op->count = 1; op->buf_fl = data; - return cdb_cmd_data(op, &cmd, sizeof(*data)); + op->cdbcmd = &cmd; + op->blocksize = sizeof(*data); + return process_op(op); } // Test unit ready @@ -104,9 +57,12 @@ cdb_test_unit_ready(struct disk_op_s *op) struct cdb_request_sense cmd; memset(&cmd, 0, sizeof(cmd)); cmd.command = CDB_CMD_TEST_UNIT_READY; + op->command = CMD_SCSI; op->count = 0; op->buf_fl = NULL; - return cdb_cmd_data(op, &cmd, 0); + op->cdbcmd = &cmd; + op->blocksize = 0; + return process_op(op); } // Request capacity @@ -116,9 +72,12 @@ cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data) struct cdb_read_capacity cmd; memset(&cmd, 0, sizeof(cmd)); cmd.command = CDB_CMD_READ_CAPACITY; + op->command = CMD_SCSI; op->count = 1; op->buf_fl = data; - return cdb_cmd_data(op, &cmd, sizeof(*data)); + op->cdbcmd = &cmd; + op->blocksize = sizeof(*data); + return process_op(op); } // Mode sense, geometry page. @@ -131,33 +90,12 @@ cdb_mode_sense_geom(struct disk_op_s *op, struct cdbres_mode_sense_geom *data) cmd.flags = 8; /* DBD */ cmd.page = MODE_PAGE_HD_GEOMETRY; cmd.count = cpu_to_be16(sizeof(*data)); + op->command = CMD_SCSI; op->count = 1; op->buf_fl = data; - return cdb_cmd_data(op, &cmd, sizeof(*data)); -} - -// Read sectors. -static int -cdb_read(struct disk_op_s *op) -{ - struct cdb_rwdata_10 cmd; - memset(&cmd, 0, sizeof(cmd)); - cmd.command = CDB_CMD_READ_10; - cmd.lba = cpu_to_be32(op->lba); - cmd.count = cpu_to_be16(op->count); - return cdb_cmd_data(op, &cmd, GET_GLOBALFLAT(op->drive_gf->blksize)); -} - -// Write sectors. -static int -cdb_write(struct disk_op_s *op) -{ - struct cdb_rwdata_10 cmd; - memset(&cmd, 0, sizeof(cmd)); - cmd.command = CDB_CMD_WRITE_10; - cmd.lba = cpu_to_be32(op->lba); - cmd.count = cpu_to_be16(op->count); - return cdb_cmd_data(op, &cmd, GET_GLOBALFLAT(op->drive_gf->blksize)); + op->cdbcmd = &cmd; + op->blocksize = sizeof(*data); + return process_op(op); } @@ -165,25 +103,36 @@ cdb_write(struct disk_op_s *op) * Main SCSI commands ****************************************************************/ -int VISIBLE32FLAT -scsi_process_op(struct disk_op_s *op) +// Create a scsi command request from a disk_op_s request +int +scsi_fill_cmd(struct disk_op_s *op, void *cdbcmd, int maxcdb) { switch (op->command) { case CMD_READ: - return cdb_read(op); - case CMD_WRITE: - return cdb_write(op); - case CMD_FORMAT: - case CMD_RESET: - case CMD_ISREADY: - case CMD_VERIFY: - case CMD_SEEK: - return DISK_RET_SUCCESS; + case CMD_WRITE: ; + struct cdb_rwdata_10 *cmd = cdbcmd; + memset(cmd, 0, maxcdb); + cmd->command = (op->command == CMD_READ ? CDB_CMD_READ_10 + : CDB_CMD_WRITE_10); + cmd->lba = cpu_to_be32(op->lba); + cmd->count = cpu_to_be16(op->count); + return GET_GLOBALFLAT(op->drive_gf->blksize); + case CMD_SCSI: + memcpy(cdbcmd, op->cdbcmd, maxcdb); + return op->blocksize; default: - return DISK_RET_EPARAM; + return -1; } } +// Determine if the command is a request to pull data from the device +int +scsi_is_read(struct disk_op_s *op) +{ + return op->command == CMD_READ || (op->command == CMD_SCSI && op->blocksize); +} + +// Check if a SCSI device is ready to receive commands int scsi_is_ready(struct disk_op_s *op) { @@ -219,7 +168,7 @@ scsi_is_ready(struct disk_op_s *op) if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) { /* IN PROGRESS OF BECOMING READY */ - printf("Waiting for device to detect medium... "); + dprintf(1, "Waiting for device to detect medium... "); /* Allow 30 seconds more */ end = timer_calc(30000); in_progress = 1; diff --git a/roms/seabios/src/hw/blockcmd.h b/roms/seabios/src/hw/blockcmd.h index df12a6d42..b543f85eb 100644 --- a/roms/seabios/src/hw/blockcmd.h +++ b/roms/seabios/src/hw/blockcmd.h @@ -100,9 +100,9 @@ struct cdbres_mode_sense_geom { } PACKED; // blockcmd.c -int cdb_is_read(u8 *cdbcmd, u16 blocksize); struct disk_op_s; -int scsi_process_op(struct disk_op_s *op); +int scsi_fill_cmd(struct disk_op_s *op, void *cdbcmd, int maxcdb); +int scsi_is_read(struct disk_op_s *op); int scsi_is_ready(struct disk_op_s *op); struct drive_s; int scsi_drive_setup(struct drive_s *drive, const char *s, int prio); diff --git a/roms/seabios/src/hw/esp-scsi.c b/roms/seabios/src/hw/esp-scsi.c index 33cc44986..d4e47e3c5 100644 --- a/roms/seabios/src/hw/esp-scsi.c +++ b/roms/seabios/src/hw/esp-scsi.c @@ -76,10 +76,19 @@ esp_scsi_dma(u32 iobase, u32 buf, u32 len, int read) outb(read ? 0x83 : 0x03, iobase + ESP_DMA_CMD); } -static int -esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op, - u8 *cdbcmd, u16 target, u16 lun, u16 blocksize) +int +esp_scsi_process_op(struct disk_op_s *op) { + if (!CONFIG_ESP_SCSI) + return DISK_RET_EBADTRACK; + struct esp_lun_s *llun_gf = + container_of(op->drive_gf, struct esp_lun_s, drive); + u16 target = GET_GLOBALFLAT(llun_gf->target); + u16 lun = GET_GLOBALFLAT(llun_gf->lun); + u8 cdbcmd[16]; + int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd)); + if (blocksize < 0) + return default_process_op(op); u32 iobase = GET_GLOBALFLAT(llun_gf->iobase); int i, state; u8 status; @@ -113,8 +122,7 @@ esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op, if (op->count && blocksize) { /* Data phase. */ u32 count = (u32)op->count * blocksize; - esp_scsi_dma(iobase, (u32)op->buf_fl, count, - cdb_is_read(cdbcmd, blocksize)); + esp_scsi_dma(iobase, (u32)op->buf_fl, count, scsi_is_read(op)); outb(ESP_CMD_TI | ESP_CMD_DMA, iobase + ESP_CMD); continue; } @@ -144,21 +152,6 @@ esp_scsi_cmd(struct esp_lun_s *llun_gf, struct disk_op_s *op, return DISK_RET_EBADTRACK; } -int -esp_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) -{ - if (!CONFIG_ESP_SCSI) - return DISK_RET_EBADTRACK; - - struct esp_lun_s *llun_gf = - container_of(op->drive_gf, struct esp_lun_s, drive); - - return esp_scsi_cmd(llun_gf, op, cdbcmd, - GET_GLOBALFLAT(llun_gf->target), - GET_GLOBALFLAT(llun_gf->lun), - blocksize); -} - static int esp_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun) { diff --git a/roms/seabios/src/hw/esp-scsi.h b/roms/seabios/src/hw/esp-scsi.h index dc555f395..0616d14b1 100644 --- a/roms/seabios/src/hw/esp-scsi.h +++ b/roms/seabios/src/hw/esp-scsi.h @@ -2,7 +2,7 @@ #define __ESP_SCSI_H struct disk_op_s; -int esp_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +int esp_scsi_process_op(struct disk_op_s *op); void esp_scsi_setup(void); #endif /* __ESP_SCSI_H */ diff --git a/roms/seabios/src/hw/floppy.c b/roms/seabios/src/hw/floppy.c index d60362a34..a14f7e093 100644 --- a/roms/seabios/src/hw/floppy.c +++ b/roms/seabios/src/hw/floppy.c @@ -613,7 +613,7 @@ floppy_format(struct disk_op_s *op) } int -process_floppy_op(struct disk_op_s *op) +floppy_process_op(struct disk_op_s *op) { if (!CONFIG_FLOPPY) return 0; diff --git a/roms/seabios/src/hw/lsi-scsi.c b/roms/seabios/src/hw/lsi-scsi.c index b1d6bbf4b..ad3352886 100644 --- a/roms/seabios/src/hw/lsi-scsi.c +++ b/roms/seabios/src/hw/lsi-scsi.c @@ -50,12 +50,21 @@ struct lsi_lun_s { u8 lun; }; -static int -lsi_scsi_cmd(struct lsi_lun_s *llun_gf, struct disk_op_s *op, - void *cdbcmd, u16 target, u16 lun, u16 blocksize) +int +lsi_scsi_process_op(struct disk_op_s *op) { + if (!CONFIG_LSI_SCSI) + return DISK_RET_EBADTRACK; + struct lsi_lun_s *llun_gf = + container_of(op->drive_gf, struct lsi_lun_s, drive); + u16 target = GET_GLOBALFLAT(llun_gf->target); + u16 lun = GET_GLOBALFLAT(llun_gf->lun); + u8 cdbcmd[16]; + int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd)); + if (blocksize < 0) + return default_process_op(op); u32 iobase = GET_GLOBALFLAT(llun_gf->iobase); - u32 dma = ((cdb_is_read(cdbcmd, blocksize) ? 0x01000000 : 0x00000000) | + u32 dma = ((scsi_is_read(op) ? 0x01000000 : 0x00000000) | (op->count * blocksize)); u8 msgout[] = { 0x80 | lun, // select lun @@ -122,21 +131,6 @@ fail: return DISK_RET_EBADTRACK; } -int -lsi_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) -{ - if (!CONFIG_LSI_SCSI) - return DISK_RET_EBADTRACK; - - struct lsi_lun_s *llun_gf = - container_of(op->drive_gf, struct lsi_lun_s, drive); - - return lsi_scsi_cmd(llun_gf, op, cdbcmd, - GET_GLOBALFLAT(llun_gf->target), - GET_GLOBALFLAT(llun_gf->lun), - blocksize); -} - static int lsi_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun) { diff --git a/roms/seabios/src/hw/lsi-scsi.h b/roms/seabios/src/hw/lsi-scsi.h index 9c5a9b212..6baf4a162 100644 --- a/roms/seabios/src/hw/lsi-scsi.h +++ b/roms/seabios/src/hw/lsi-scsi.h @@ -2,7 +2,7 @@ #define __LSI_SCSI_H struct disk_op_s; -int lsi_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +int lsi_scsi_process_op(struct disk_op_s *op); void lsi_scsi_setup(void); #endif /* __LSI_SCSI_H */ diff --git a/roms/seabios/src/hw/megasas.c b/roms/seabios/src/hw/megasas.c index b2a65e48b..cb1a2a653 100644 --- a/roms/seabios/src/hw/megasas.c +++ b/roms/seabios/src/hw/megasas.c @@ -157,18 +157,20 @@ static int megasas_fire_cmd(u16 pci_id, u32 ioaddr, } int -megasas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +megasas_process_op(struct disk_op_s *op) { + if (!CONFIG_MEGASAS) + return DISK_RET_EBADTRACK; + u8 cdb[16]; + int blocksize = scsi_fill_cmd(op, cdb, sizeof(cdb)); + if (blocksize < 0) + return default_process_op(op); struct megasas_lun_s *mlun_gf = container_of(op->drive_gf, struct megasas_lun_s, drive); - u8 *cdb = cdbcmd; struct megasas_cmd_frame *frame = GET_GLOBALFLAT(mlun_gf->frame); u16 pci_id = GET_GLOBALFLAT(mlun_gf->pci_id); int i; - if (!CONFIG_MEGASAS) - return DISK_RET_EBADTRACK; - memset_fl(frame, 0, sizeof(*frame)); SET_LOWFLAT(frame->cmd, MFI_CMD_LD_SCSI_IO); SET_LOWFLAT(frame->cmd_status, 0xFF); @@ -241,7 +243,10 @@ static void megasas_scan_target(struct pci_device *pci, u32 iobase) { struct mfi_ld_list_s ld_list; struct megasas_cmd_frame *frame = memalign_tmp(256, sizeof(*frame)); - int i; + if (!frame) { + warn_noalloc(); + return; + } memset(&ld_list, 0, sizeof(ld_list)); memset_fl(frame, 0, sizeof(*frame)); @@ -258,6 +263,7 @@ static void megasas_scan_target(struct pci_device *pci, u32 iobase) if (megasas_fire_cmd(pci->device, iobase, frame) == 0) { dprintf(2, "%d LD found\n", ld_list.count); + int i; for (i = 0; i < ld_list.count; i++) { dprintf(2, "LD %d:%d state 0x%x\n", ld_list.lds[i].target, ld_list.lds[i].lun, @@ -295,9 +301,9 @@ static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr) pci->device == PCI_DEVICE_ID_LSI_SAS2008 || pci->device == PCI_DEVICE_ID_LSI_SAS2208 || pci->device == PCI_DEVICE_ID_LSI_SAS3108) { - outl(ioaddr + MFI_DB, mfi_flags); + outl(mfi_flags, ioaddr + MFI_DB); } else { - outl(ioaddr + MFI_IDB, mfi_flags); + outl(mfi_flags, ioaddr + MFI_IDB); } break; case MFI_STATE_OPERATIONAL: @@ -306,7 +312,7 @@ static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr) pci->device == PCI_DEVICE_ID_LSI_SAS2008 || pci->device == PCI_DEVICE_ID_LSI_SAS2208 || pci->device == PCI_DEVICE_ID_LSI_SAS3108) { - outl(ioaddr + MFI_DB, mfi_flags); + outl(mfi_flags, ioaddr + MFI_DB); if (pci->device == PCI_DEVICE_ID_LSI_SAS2208 || pci->device == PCI_DEVICE_ID_LSI_SAS3108) { int j = 0; @@ -321,7 +327,7 @@ static int megasas_transition_to_ready(struct pci_device *pci, u32 ioaddr) } } } else { - outw(ioaddr + MFI_IDB, mfi_flags); + outl(mfi_flags, ioaddr + MFI_IDB); } break; case MFI_STATE_READY: diff --git a/roms/seabios/src/hw/megasas.h b/roms/seabios/src/hw/megasas.h index 124042e1c..ed0e4f096 100644 --- a/roms/seabios/src/hw/megasas.h +++ b/roms/seabios/src/hw/megasas.h @@ -2,7 +2,7 @@ #define __MEGASAS_H struct disk_op_s; -int megasas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +int megasas_process_op(struct disk_op_s *op); void megasas_setup(void); #endif /* __MEGASAS_H */ diff --git a/roms/seabios/src/hw/pci.c b/roms/seabios/src/hw/pci.c index 0379b558e..a241d0675 100644 --- a/roms/seabios/src/hw/pci.c +++ b/roms/seabios/src/hw/pci.c @@ -221,16 +221,21 @@ pci_find_init_device(const struct pci_device_id *ids, void *arg) return NULL; } -u8 pci_find_capability(struct pci_device *pci, u8 cap_id) +u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap) { int i; - u8 cap; u16 status = pci_config_readw(pci->bdf, PCI_STATUS); if (!(status & PCI_STATUS_CAP_LIST)) return 0; - cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST); + if (cap == 0) { + /* find first */ + cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST); + } else { + /* find next */ + cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT); + } for (i = 0; cap && i <= 0xff; i++) { if (pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_ID) == cap_id) return cap; diff --git a/roms/seabios/src/hw/pci.h b/roms/seabios/src/hw/pci.h index 0aaa84c1a..fc5e7b9bf 100644 --- a/roms/seabios/src/hw/pci.h +++ b/roms/seabios/src/hw/pci.h @@ -123,7 +123,7 @@ int pci_init_device(const struct pci_device_id *ids , struct pci_device *pci, void *arg); struct pci_device *pci_find_init_device(const struct pci_device_id *ids , void *arg); -u8 pci_find_capability(struct pci_device *pci, u8 cap_id); +u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap); int pci_bridge_has_region(struct pci_device *pci, enum pci_region_type region_type); void pci_reboot(void); diff --git a/roms/seabios/src/hw/pci_ids.h b/roms/seabios/src/hw/pci_ids.h index 1cd4f7269..cdf9b3cbc 100644 --- a/roms/seabios/src/hw/pci_ids.h +++ b/roms/seabios/src/hw/pci_ids.h @@ -2616,8 +2616,12 @@ #define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 -#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 -#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 +/* virtio 0.9.5 ids (legacy/transitional devices) */ +#define PCI_DEVICE_ID_VIRTIO_BLK_09 0x1001 +#define PCI_DEVICE_ID_VIRTIO_SCSI_09 0x1004 +/* virtio 1.0 ids (modern devices) */ +#define PCI_DEVICE_ID_VIRTIO_BLK_10 0x1042 +#define PCI_DEVICE_ID_VIRTIO_SCSI_10 0x1048 #define PCI_VENDOR_ID_VMWARE 0x15ad #define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 diff --git a/roms/seabios/src/hw/pic.c b/roms/seabios/src/hw/pic.c index 6ff696765..d8b9764c7 100644 --- a/roms/seabios/src/hw/pic.c +++ b/roms/seabios/src/hw/pic.c @@ -13,12 +13,16 @@ u16 pic_irqmask_read(void) { + if (!CONFIG_HARDWARE_IRQ) + return 0; return inb(PORT_PIC1_DATA) | (inb(PORT_PIC2_DATA) << 8); } void pic_irqmask_write(u16 mask) { + if (!CONFIG_HARDWARE_IRQ) + return; outb(mask, PORT_PIC1_DATA); outb(mask >> 8, PORT_PIC2_DATA); } @@ -26,6 +30,8 @@ pic_irqmask_write(u16 mask) void pic_irqmask_mask(u16 off, u16 on) { + if (!CONFIG_HARDWARE_IRQ) + return; u8 pic1off = off, pic1on = on, pic2off = off>>8, pic2on = on>>8; outb((inb(PORT_PIC1_DATA) & ~pic1off) | pic1on, PORT_PIC1_DATA); outb((inb(PORT_PIC2_DATA) & ~pic2off) | pic2on, PORT_PIC2_DATA); @@ -34,6 +40,8 @@ pic_irqmask_mask(u16 off, u16 on) void pic_reset(u8 irq0, u8 irq8) { + if (!CONFIG_HARDWARE_IRQ) + return; // Send ICW1 (select OCW1 + will send ICW4) outb(0x11, PORT_PIC1_CMD); outb(0x11, PORT_PIC2_CMD); @@ -60,6 +68,8 @@ pic_setup(void) void enable_hwirq(int hwirq, struct segoff_s func) { + if (!CONFIG_HARDWARE_IRQ) + return; pic_irqmask_mask(1 << hwirq, 0); int vector; if (hwirq < 8) @@ -72,6 +82,8 @@ enable_hwirq(int hwirq, struct segoff_s func) static u8 pic_isr1_read(void) { + if (!CONFIG_HARDWARE_IRQ) + return 0; // 0x0b == select OCW1 + read ISR outb(0x0b, PORT_PIC1_CMD); return inb(PORT_PIC1_CMD); @@ -80,6 +92,8 @@ pic_isr1_read(void) static u8 pic_isr2_read(void) { + if (!CONFIG_HARDWARE_IRQ) + return 0; // 0x0b == select OCW1 + read ISR outb(0x0b, PORT_PIC2_CMD); return inb(PORT_PIC2_CMD); diff --git a/roms/seabios/src/hw/pic.h b/roms/seabios/src/hw/pic.h index 6947b6e81..f2d9f6130 100644 --- a/roms/seabios/src/hw/pic.h +++ b/roms/seabios/src/hw/pic.h @@ -34,6 +34,8 @@ static inline void pic_eoi1(void) { + if (!CONFIG_HARDWARE_IRQ) + return; // Send eoi (select OCW2 + eoi) outb(0x20, PORT_PIC1_CMD); } @@ -41,6 +43,8 @@ pic_eoi1(void) static inline void pic_eoi2(void) { + if (!CONFIG_HARDWARE_IRQ) + return; // Send eoi (select OCW2 + eoi) outb(0x20, PORT_PIC2_CMD); pic_eoi1(); diff --git a/roms/seabios/src/hw/ps2port.c b/roms/seabios/src/hw/ps2port.c index 04995c881..d5504f71e 100644 --- a/roms/seabios/src/hw/ps2port.c +++ b/roms/seabios/src/hw/ps2port.c @@ -210,7 +210,7 @@ ps2_sendbyte(int aux, u8 command, int timeout) return 0; } -u8 Ps2ctr VARLOW; +u8 Ps2ctr VARLOW = I8042_CTR_KBDDIS | I8042_CTR_AUXDIS; static int __ps2_command(int aux, int command, u8 *param) @@ -232,6 +232,7 @@ __ps2_command(int aux, int command, u8 *param) yield(); // Enable port command is being sent to. + SET_LOW(Ps2ctr, newctr); if (aux) newctr &= ~I8042_CTR_AUXDIS; else @@ -240,8 +241,8 @@ __ps2_command(int aux, int command, u8 *param) if (ret) goto fail; - if (command == ATKBD_CMD_RESET_BAT) { - // Reset is special wrt timeouts and bytes received. + if ((u8)command == (u8)ATKBD_CMD_RESET_BAT) { + // Reset is special wrt timeouts. // Send command. ret = ps2_sendbyte(aux, command, 1000); @@ -253,11 +254,12 @@ __ps2_command(int aux, int command, u8 *param) if (ret < 0) goto fail; param[0] = ret; - ret = ps2_recvbyte(aux, 0, 100); - if (ret < 0) - // Some devices only respond with one byte on reset. - ret = 0; - param[1] = ret; + if (receive > 1) { + ret = ps2_recvbyte(aux, 0, 500); + if (ret < 0) + goto fail; + param[1] = ret; + } } else if (command == ATKBD_CMD_GETID) { // Getid is special wrt bytes received. @@ -308,6 +310,7 @@ __ps2_command(int aux, int command, u8 *param) fail: // Restore interrupts and keyboard/mouse. + SET_LOW(Ps2ctr, ps2ctr); ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr); if (ret2) return ret2; @@ -343,7 +346,8 @@ ps2_mouse_command(int command, u8 *param) if (command == PSMOUSE_CMD_ENABLE || command == PSMOUSE_CMD_DISABLE) { u8 ps2ctr = GET_LOW(Ps2ctr); if (command == PSMOUSE_CMD_ENABLE) - ps2ctr = (ps2ctr | I8042_CTR_AUXINT) & ~I8042_CTR_AUXDIS; + ps2ctr = ((ps2ctr | (CONFIG_HARDWARE_IRQ ? I8042_CTR_AUXINT : 0)) + & ~I8042_CTR_AUXDIS); else ps2ctr = (ps2ctr | I8042_CTR_AUXDIS) & ~I8042_CTR_AUXINT; SET_LOW(Ps2ctr, ps2ctr); @@ -414,6 +418,31 @@ done: pic_eoi1(); } +// Check for ps2 activity on machines without hardware irqs +void +ps2_check_event(void) +{ + if (! CONFIG_PS2PORT || CONFIG_HARDWARE_IRQ) + return; + u8 ps2ctr = GET_LOW(Ps2ctr); + if ((ps2ctr & (I8042_CTR_KBDDIS|I8042_CTR_AUXDIS)) + == (I8042_CTR_KBDDIS|I8042_CTR_AUXDIS)) + return; + for (;;) { + u8 status = inb(PORT_PS2_STATUS); + if (!(status & I8042_STR_OBF)) + break; + u8 data = inb(PORT_PS2_DATA); + if (status & I8042_STR_AUXDATA) { + if (!(ps2ctr & I8042_CTR_AUXDIS)) + process_mouse(data); + } else { + if (!(ps2ctr & I8042_CTR_KBDDIS)) + process_key(data); + } + } +} + /**************************************************************** * Setup @@ -446,9 +475,6 @@ ps2_keyboard_setup(void *data) return; } - // Disable keyboard and mouse events. - SET_LOW(Ps2ctr, I8042_CTR_KBDDIS | I8042_CTR_AUXDIS); - /* ------------------- keyboard side ------------------------*/ /* reset keyboard and self test (keyboard side) */ @@ -482,7 +508,8 @@ ps2_keyboard_setup(void *data) return; // Keyboard Mode: disable mouse, scan code convert, enable kbd IRQ - SET_LOW(Ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT); + Ps2ctr = (I8042_CTR_AUXDIS | I8042_CTR_XLATE + | (CONFIG_HARDWARE_IRQ ? I8042_CTR_KBDINT : 0)); /* Enable keyboard */ ret = ps2_kbd_command(ATKBD_CMD_ENABLE, NULL); diff --git a/roms/seabios/src/hw/ps2port.h b/roms/seabios/src/hw/ps2port.h index e5d9014b7..1338406ac 100644 --- a/roms/seabios/src/hw/ps2port.h +++ b/roms/seabios/src/hw/ps2port.h @@ -26,7 +26,7 @@ #define ATKBD_CMD_GETID 0x02f2 #define ATKBD_CMD_ENABLE 0x00f4 #define ATKBD_CMD_RESET_DIS 0x00f5 -#define ATKBD_CMD_RESET_BAT 0x02ff +#define ATKBD_CMD_RESET_BAT 0x01ff // Mouse commands #define PSMOUSE_CMD_SETSCALE11 0x00e6 @@ -61,6 +61,7 @@ void i8042_reboot(void); int ps2_kbd_command(int command, u8 *param); int ps2_mouse_command(int command, u8 *param); +void ps2_check_event(void); void ps2port_setup(void); #endif // ps2port.h diff --git a/roms/seabios/src/hw/pvscsi.c b/roms/seabios/src/hw/pvscsi.c index 601a551db..fa20efef7 100644 --- a/roms/seabios/src/hw/pvscsi.c +++ b/roms/seabios/src/hw/pvscsi.c @@ -11,6 +11,7 @@ #include "blockcmd.h" // scsi_drive_setup #include "config.h" // CONFIG_* #include "malloc.h" // free +#include "memmap.h" // PAGE_SHIFT, virt_to_phys #include "output.h" // dprintf #include "pci.h" // foreachpci #include "pci_ids.h" // PCI_DEVICE_ID_VMWARE_PVSCSI @@ -19,7 +20,6 @@ #include "std/disk.h" // DISK_RET_SUCCESS #include "string.h" // memset #include "util.h" // usleep -#include "virtio-ring.h" // PAGE_SHIFT, virt_to_phys #include "x86.h" // writel #define MASK(n) ((1 << (n)) - 1) @@ -197,29 +197,6 @@ pvscsi_init_rings(void *iobase, struct pvscsi_ring_dsc_s **ring_dsc) *ring_dsc = dsc; } -static void pvscsi_fill_req(struct PVSCSIRingsState *s, - struct PVSCSIRingReqDesc *req, - u16 target, u16 lun, void *cdbcmd, u16 blocksize, - struct disk_op_s *op) -{ - req->bus = 0; - req->target = target; - memset(req->lun, 0, sizeof(req->lun)); - req->lun[1] = lun; - req->senseLen = 0; - req->senseAddr = 0; - req->cdbLen = 16; - req->vcpuHint = 0; - memcpy(req->cdb, cdbcmd, 16); - req->tag = SIMPLE_QUEUE_TAG; - req->flags = cdb_is_read(cdbcmd, blocksize) ? - PVSCSI_FLAG_CMD_DIR_TOHOST : PVSCSI_FLAG_CMD_DIR_TODEVICE; - - req->dataLen = op->count * blocksize; - req->dataAddr = (u32)op->buf_fl; - s->reqProdIdx = s->reqProdIdx + 1; -} - static u32 pvscsi_get_rsp(struct PVSCSIRingsState *s, struct PVSCSIRingCmpDesc *rsp) @@ -229,10 +206,13 @@ pvscsi_get_rsp(struct PVSCSIRingsState *s, return status; } -static int -pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op, - void *cdbcmd, u16 target, u16 lun, u16 blocksize) +int +pvscsi_process_op(struct disk_op_s *op) { + if (!CONFIG_PVSCSI) + return DISK_RET_EBADTRACK; + struct pvscsi_lun_s *plun = + container_of(op->drive_gf, struct pvscsi_lun_s, drive); struct pvscsi_ring_dsc_s *ring_dsc = plun->ring_dsc; struct PVSCSIRingsState *s = ring_dsc->ring_state; u32 req_entries = s->reqNumEntriesLog2; @@ -248,7 +228,23 @@ pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op, } req = ring_dsc->ring_reqs + (s->reqProdIdx & MASK(req_entries)); - pvscsi_fill_req(s, req, target, lun, cdbcmd, blocksize, op); + int blocksize = scsi_fill_cmd(op, req->cdb, 16); + if (blocksize < 0) + return default_process_op(op); + req->bus = 0; + req->target = plun->target; + memset(req->lun, 0, sizeof(req->lun)); + req->lun[1] = plun->lun; + req->senseLen = 0; + req->senseAddr = 0; + req->cdbLen = 16; + req->vcpuHint = 0; + req->tag = SIMPLE_QUEUE_TAG; + req->flags = scsi_is_read(op) ? + PVSCSI_FLAG_CMD_DIR_TOHOST : PVSCSI_FLAG_CMD_DIR_TODEVICE; + req->dataLen = op->count * blocksize; + req->dataAddr = (u32)op->buf_fl; + s->reqProdIdx = s->reqProdIdx + 1; pvscsi_kick_rw_io(plun->iobase); pvscsi_wait_intr_cmpl(plun->iobase); @@ -259,18 +255,6 @@ pvscsi_cmd(struct pvscsi_lun_s *plun, struct disk_op_s *op, return status == 0 ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; } -int -pvscsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) -{ - if (!CONFIG_PVSCSI) - return DISK_RET_EBADTRACK; - - struct pvscsi_lun_s *plun = - container_of(op->drive_gf, struct pvscsi_lun_s, drive); - - return pvscsi_cmd(plun, op, cdbcmd, plun->target, plun->lun, blocksize); -} - static int pvscsi_add_lun(struct pci_device *pci, void *iobase, struct pvscsi_ring_dsc_s *ring_dsc, u8 target, u8 lun) diff --git a/roms/seabios/src/hw/pvscsi.h b/roms/seabios/src/hw/pvscsi.h index fde9f0b98..5af7dcb0e 100644 --- a/roms/seabios/src/hw/pvscsi.h +++ b/roms/seabios/src/hw/pvscsi.h @@ -2,7 +2,7 @@ #define _PVSCSI_H_ struct disk_op_s; -int pvscsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +int pvscsi_process_op(struct disk_op_s *op); void pvscsi_setup(void); #endif /* _PVSCSI_H_ */ diff --git a/roms/seabios/src/hw/ramdisk.c b/roms/seabios/src/hw/ramdisk.c index 1177bc00a..adec1d1b3 100644 --- a/roms/seabios/src/hw/ramdisk.c +++ b/roms/seabios/src/hw/ramdisk.c @@ -7,8 +7,9 @@ #include "biosvar.h" // GET_GLOBALFLAT #include "block.h" // struct drive_s #include "bregs.h" // struct bregs -#include "malloc.h" // malloc_fseg -#include "memmap.h" // add_e820 +#include "e820map.h" // e820_add +#include "malloc.h" // memalign_tmphigh +#include "memmap.h" // PAGE_SIZE #include "output.h" // dprintf #include "romfile.h" // romfile_findprefix #include "stacks.h" // call16_int @@ -41,7 +42,7 @@ ramdisk_setup(void) warn_noalloc(); return; } - add_e820((u32)pos, size, E820_RESERVED); + e820_add((u32)pos, size, E820_RESERVED); // Copy image into ram. int ret = file->copy(file, pos, size); @@ -53,7 +54,7 @@ ramdisk_setup(void) if (!drive) return; drive->type = DTYPE_RAMDISK; - dprintf(1, "Mapping CBFS floppy %s to addr %p\n", filename, pos); + dprintf(1, "Mapping floppy %s to addr %p\n", filename, pos); char *desc = znprintf(MAXDESCSIZE, "Ramdisk [%s]", &filename[10]); boot_add_floppy(drive, desc, bootprio_find_named_rom(filename, 0)); } @@ -91,7 +92,7 @@ ramdisk_copy(struct disk_op_s *op, int iswrite) } int -process_ramdisk_op(struct disk_op_s *op) +ramdisk_process_op(struct disk_op_s *op) { if (!CONFIG_FLASH_FLOPPY) return 0; @@ -101,11 +102,7 @@ process_ramdisk_op(struct disk_op_s *op) return ramdisk_copy(op, 0); case CMD_WRITE: return ramdisk_copy(op, 1); - case CMD_VERIFY: - case CMD_FORMAT: - case CMD_RESET: - return DISK_RET_SUCCESS; default: - return DISK_RET_EPARAM; + return default_process_op(op); } } diff --git a/roms/seabios/src/hw/rtc.c b/roms/seabios/src/hw/rtc.c index 628d5429f..9649a5a79 100644 --- a/roms/seabios/src/hw/rtc.c +++ b/roms/seabios/src/hw/rtc.c @@ -30,6 +30,7 @@ rtc_write(u8 index, u8 val) void rtc_mask(u8 index, u8 off, u8 on) { + index |= NMI_DISABLE_BIT; outb(index, PORT_CMOS_INDEX); u8 val = inb(PORT_CMOS_DATA); outb((val & ~off) | on, PORT_CMOS_DATA); @@ -62,6 +63,8 @@ rtc_updating(void) void rtc_setup(void) { + if (!CONFIG_RTC_TIMER) + return; rtc_write(CMOS_STATUS_A, 0x26); // 32,768Khz src, 976.5625us updates rtc_mask(CMOS_STATUS_B, ~RTC_B_DSE, RTC_B_24HR); rtc_read(CMOS_STATUS_C); @@ -73,6 +76,8 @@ int RTCusers VARLOW; void rtc_use(void) { + if (!CONFIG_RTC_TIMER) + return; int count = GET_LOW(RTCusers); SET_LOW(RTCusers, count+1); if (count) @@ -84,6 +89,8 @@ rtc_use(void) void rtc_release(void) { + if (!CONFIG_RTC_TIMER) + return; int count = GET_LOW(RTCusers); SET_LOW(RTCusers, count-1); if (count != 1) diff --git a/roms/seabios/src/hw/sdcard.c b/roms/seabios/src/hw/sdcard.c index 6ff93c856..e01e1bb02 100644 --- a/roms/seabios/src/hw/sdcard.c +++ b/roms/seabios/src/hw/sdcard.c @@ -5,12 +5,12 @@ // This file may be distributed under the terms of the GNU LGPLv3 license. #include "block.h" // struct drive_s -#include "fw/paravirt.h" // runningOnQEMU #include "malloc.h" // malloc_fseg #include "output.h" // znprintf #include "pci.h" // pci_config_readl #include "pci_ids.h" // PCI_CLASS_SYSTEM_SDHCI #include "pci_regs.h" // PCI_BASE_ADDRESS_0 +#include "romfile.h" // romfile_findprefix #include "stacks.h" // wait_preempt #include "std/disk.h" // DISK_RET_SUCCESS #include "string.h" // memset @@ -42,8 +42,8 @@ struct sdhci_s { u16 irq_signal; u16 error_signal; u16 auto_cmd12; - u8 pad_3E[2]; - u64 cap; + u16 host_control2; + u32 cap_lo, cap_hi; u64 max_current; u16 force_auto_cmd12; u16 force_error; @@ -56,25 +56,38 @@ struct sdhci_s { } PACKED; // SDHCI commands -#define SC_ALL_SEND_CID ((2<<8) | 0x21) -#define SC_SEND_RELATIVE_ADDR ((3<<8) | 0x22) -#define SC_SELECT_DESELECT_CARD ((7<<8) | 0x23) -#define SC_READ_SINGLE ((17<<8) | 0x22) -#define SC_READ_MULTIPLE ((18<<8) | 0x22) -#define SC_WRITE_SINGLE ((24<<8) | 0x22) -#define SC_WRITE_MULTIPLE ((25<<8) | 0x22) -#define SC_APP_CMD ((55<<8) | 0x22) -#define SC_APP_SEND_OP_COND ((41<<8) | 0x22) +#define SCB_R0 0x00 // No response +#define SCB_R48 0x1a // Response R1 (no data), R5, R6, R7 +#define SCB_R48d 0x3a // Response R1 (with data) +#define SCB_R48b 0x1b // Response R1b, R5b +#define SCB_R48o 0x02 // Response R3, R4 +#define SCB_R136 0x09 // Response R2 +#define SC_GO_IDLE_STATE ((0<<8) | SCB_R0) +#define SC_SEND_OP_COND ((1<<8) | SCB_R48o) +#define SC_ALL_SEND_CID ((2<<8) | SCB_R136) +#define SC_SEND_RELATIVE_ADDR ((3<<8) | SCB_R48) +#define SC_SELECT_DESELECT_CARD ((7<<8) | SCB_R48b) +#define SC_SEND_IF_COND ((8<<8) | SCB_R48) +#define SC_SEND_EXT_CSD ((8<<8) | SCB_R48d) +#define SC_SEND_CSD ((9<<8) | SCB_R136) +#define SC_READ_SINGLE ((17<<8) | SCB_R48d) +#define SC_READ_MULTIPLE ((18<<8) | SCB_R48d) +#define SC_WRITE_SINGLE ((24<<8) | SCB_R48d) +#define SC_WRITE_MULTIPLE ((25<<8) | SCB_R48d) +#define SC_APP_CMD ((55<<8) | SCB_R48) +#define SC_APP_SEND_OP_COND ((41<<8) | SCB_R48o) // SDHCI irqs #define SI_CMD_COMPLETE (1<<0) #define SI_TRANS_DONE (1<<1) #define SI_WRITE_READY (1<<4) #define SI_READ_READY (1<<5) +#define SI_ERROR (1<<15) // SDHCI present_state flags -#define SP_CMD_INHIBIT (1<<0) -#define SP_DAT_INHIBIT (1<<1) +#define SP_CMD_INHIBIT (1<<0) +#define SP_DAT_INHIBIT (1<<1) +#define SP_CARD_INSERTED (1<<16) // SDHCI transfer_mode flags #define ST_BLOCKCOUNT (1<<1) @@ -82,12 +95,43 @@ struct sdhci_s { #define ST_READ (1<<4) #define ST_MULTIPLE (1<<5) +// SDHCI capabilities flags +#define SD_CAPLO_V33 (1<<24) +#define SD_CAPLO_V30 (1<<25) +#define SD_CAPLO_V18 (1<<26) +#define SD_CAPLO_BASECLOCK_SHIFT 8 +#define SD_CAPLO_BASECLOCK_MASK 0xff + +// SDHCI clock control flags +#define SCC_INTERNAL_ENABLE (1<<0) +#define SCC_STABLE (1<<1) +#define SCC_CLOCK_ENABLE (1<<2) +#define SCC_SDCLK_MASK 0xff +#define SCC_SDCLK_SHIFT 8 +#define SCC_SDCLK_HI_MASK 0x300 +#define SCC_SDCLK_HI_RSHIFT 2 + +// SDHCI power control flags +#define SPC_POWER_ON (1<<0) +#define SPC_V18 0x0a +#define SPC_V30 0x0c +#define SPC_V33 0x0e + +// SDHCI software reset flags +#define SRF_ALL 0x01 +#define SRF_CMD 0x02 +#define SRF_DATA 0x04 + // SDHCI result flags -#define SR_OCR_CCS (1<<30) +#define SR_OCR_CCS (1<<30) +#define SR_OCR_NOTBUSY (1<<31) // SDHCI timeouts -#define SDHCI_PIO_TIMEOUT 1000 // XXX - these are just made up -#define SDHCI_TRANSFER_TIMEOUT 10000 +#define SDHCI_POWER_OFF_TIME 1 +#define SDHCI_POWER_ON_TIME 1 +#define SDHCI_CLOCK_ON_TIME 1 // 74 clock cycles +#define SDHCI_POWERUP_TIMEOUT 1000 +#define SDHCI_PIO_TIMEOUT 1000 // XXX - this is just made up // Internal 'struct drive_s' storage for a detected card struct sddrive_s { @@ -97,18 +141,18 @@ struct sddrive_s { }; // SD card types -#define SF_MMC 0 -#define SF_SDSC 1 -#define SF_SDHC 2 +#define SF_MMC (1<<0) +#define SF_HIGHCAPACITY (1<<1) -// Repeatedly read a u16 register until the specific value is found +// Repeatedly read a u16 register until any bit in a given mask is set static int -waitw(u16 *reg, u16 mask, u16 value, u32 end) +sdcard_waitw(u16 *reg, u16 mask) { + u32 end = timer_calc(SDHCI_PIO_TIMEOUT); for (;;) { u16 v = readw(reg); - if ((v & mask) == value) - return 0; + if (v & mask) + return v; if (timer_check(end)) { warn_timeout(); return -1; @@ -117,24 +161,49 @@ waitw(u16 *reg, u16 mask, u16 value, u32 end) } } +// Send an sdhci reset +static int +sdcard_reset(struct sdhci_s *regs, int flags) +{ + writeb(®s->software_reset, flags); + u32 end = timer_calc(SDHCI_PIO_TIMEOUT); + while (readb(®s->software_reset)) + if (timer_check(end)) { + warn_timeout(); + return -1; + } + return 0; +} + // Send a command to the card. static int sdcard_pio(struct sdhci_s *regs, int cmd, u32 *param) { - u32 end = timer_calc(SDHCI_PIO_TIMEOUT); - u16 busyf = SP_CMD_INHIBIT | ((cmd & 0x03) == 0x03 ? SP_DAT_INHIBIT : 0); - int ret = waitw((u16*)®s->present_state, busyf, 0, end); - if (ret) - return ret; + u32 state = readl(®s->present_state); + dprintf(9, "sdcard_pio cmd %x %x %x\n", cmd, *param, state); + if ((state & SP_CMD_INHIBIT) + || ((cmd & 0x03) == 0x03 && state & SP_DAT_INHIBIT)) { + dprintf(1, "sdcard_pio not ready %x\n", state); + return -1; + } // Send command writel(®s->arg, *param); writew(®s->cmd, cmd); - ret = waitw(®s->irq_status, SI_CMD_COMPLETE, SI_CMD_COMPLETE, end); - if (ret) + int ret = sdcard_waitw(®s->irq_status, SI_ERROR|SI_CMD_COMPLETE); + if (ret < 0) return ret; + if (ret & SI_ERROR) { + u16 err = readw(®s->error_irq_status); + dprintf(3, "sdcard_pio command stop (code=%x)\n", err); + sdcard_reset(regs, SRF_CMD|SRF_DATA); + writew(®s->error_irq_status, err); + return -1; + } writew(®s->irq_status, SI_CMD_COMPLETE); // Read response memcpy(param, regs->response, sizeof(regs->response)); + dprintf(9, "sdcard cmd %x response %x %x %x %x\n" + , cmd, param[0], param[1], param[2], param[3]); return 0; } @@ -155,24 +224,23 @@ sdcard_pio_transfer(struct sddrive_s *drive, int cmd, u32 addr , void *data, int count) { // Send command - writel(&drive->regs->block_size, DISK_SECTOR_SIZE); - writew(&drive->regs->block_count, count); // XXX - SC_SET_BLOCK_COUNT? + writew(&drive->regs->block_size, DISK_SECTOR_SIZE); + writew(&drive->regs->block_count, count); int isread = cmd != SC_WRITE_SINGLE && cmd != SC_WRITE_MULTIPLE; u16 tmode = ((count > 1 ? ST_MULTIPLE|ST_AUTO_CMD12|ST_BLOCKCOUNT : 0) | (isread ? ST_READ : 0)); writew(&drive->regs->transfer_mode, tmode); - if (drive->card_type < SF_SDHC) + if (!(drive->card_type & SF_HIGHCAPACITY)) addr *= DISK_SECTOR_SIZE; u32 param[4] = { addr }; int ret = sdcard_pio(drive->regs, cmd, param); if (ret) return ret; // Read/write data - u32 end = timer_calc(SDHCI_TRANSFER_TIMEOUT); u16 cbit = isread ? SI_READ_READY : SI_WRITE_READY; while (count--) { - ret = waitw(&drive->regs->irq_status, cbit, cbit, end); - if (ret) + ret = sdcard_waitw(&drive->regs->irq_status, cbit); + if (ret < 0) return ret; writew(&drive->regs->irq_status, cbit); int i; @@ -185,9 +253,8 @@ sdcard_pio_transfer(struct sddrive_s *drive, int cmd, u32 addr } } // Complete command - // XXX - SC_STOP_TRANSMISSION? - ret = waitw(&drive->regs->irq_status, SI_TRANS_DONE, SI_TRANS_DONE, end); - if (ret) + ret = sdcard_waitw(&drive->regs->irq_status, SI_TRANS_DONE); + if (ret < 0) return ret; writew(&drive->regs->irq_status, SI_TRANS_DONE); return 0; @@ -208,8 +275,8 @@ sdcard_readwrite(struct disk_op_s *op, int iswrite) return DISK_RET_SUCCESS; } -int VISIBLE32FLAT -process_sdcard_op(struct disk_op_s *op) +int +sdcard_process_op(struct disk_op_s *op) { if (!CONFIG_SDCARD) return 0; @@ -218,14 +285,8 @@ process_sdcard_op(struct disk_op_s *op) return sdcard_readwrite(op, 0); case CMD_WRITE: return sdcard_readwrite(op, 1); - case CMD_FORMAT: - case CMD_RESET: - case CMD_ISREADY: - case CMD_VERIFY: - case CMD_SEEK: - return DISK_RET_SUCCESS; default: - return DISK_RET_EPARAM; + return default_process_op(op); } } @@ -234,75 +295,253 @@ process_sdcard_op(struct disk_op_s *op) * Setup ****************************************************************/ +static int +sdcard_set_power(struct sdhci_s *regs) +{ + u32 cap = readl(®s->cap_lo); + u32 volt, vbits; + if (cap & SD_CAPLO_V33) { + volt = 1<<20; + vbits = SPC_V33; + } else if (cap & SD_CAPLO_V30) { + volt = 1<<18; + vbits = SPC_V30; + } else if (cap & SD_CAPLO_V18) { + volt = 1<<7; + vbits = SPC_V18; + } else { + dprintf(1, "SD controller unsupported volt range (%x)\n", cap); + return -1; + } + writeb(®s->power_control, 0); + msleep(SDHCI_POWER_OFF_TIME); + writeb(®s->power_control, vbits | SPC_POWER_ON); + msleep(SDHCI_POWER_ON_TIME); + return volt; +} + +static int +sdcard_set_frequency(struct sdhci_s *regs, u32 khz) +{ + u16 ver = readw(®s->controller_version); + u32 cap = readl(®s->cap_lo); + u32 base_freq = (cap >> SD_CAPLO_BASECLOCK_SHIFT) & SD_CAPLO_BASECLOCK_MASK; + if (!base_freq) { + dprintf(1, "Unknown base frequency for SD controller\n"); + return -1; + } + // Set new frequency + u32 divisor = DIV_ROUND_UP(base_freq * 1000, khz); + u16 creg; + if ((ver & 0xff) <= 0x01) { + divisor = divisor > 1 ? 1 << __fls(divisor-1) : 0; + creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT; + } else { + divisor = DIV_ROUND_UP(divisor, 2); + creg = (divisor & SCC_SDCLK_MASK) << SCC_SDCLK_SHIFT; + creg |= (divisor & SCC_SDCLK_HI_MASK) >> SCC_SDCLK_HI_RSHIFT; + } + dprintf(3, "sdcard_set_frequency %d %d %x\n", base_freq, khz, creg); + writew(®s->clock_control, 0); + writew(®s->clock_control, creg | SCC_INTERNAL_ENABLE); + // Wait for frequency to become active + int ret = sdcard_waitw(®s->clock_control, SCC_STABLE); + if (ret < 0) + return ret; + // Enable SD clock + writew(®s->clock_control, creg | SCC_INTERNAL_ENABLE | SCC_CLOCK_ENABLE); + return 0; +} + +// Obtain the disk size of an SD card +static int +sdcard_get_capacity(struct sddrive_s *drive, u8 *csd) +{ + // Original MMC/SD card capacity formula + u16 C_SIZE = (csd[6] >> 6) | (csd[7] << 2) | ((csd[8] & 0x03) << 10); + u8 C_SIZE_MULT = (csd[4] >> 7) | ((csd[5] & 0x03) << 1); + u8 READ_BL_LEN = csd[9] & 0x0f; + u32 count = (C_SIZE+1) << (C_SIZE_MULT + 2 + READ_BL_LEN - 9); + // Check for newer encoding formats. + u8 CSD_STRUCTURE = csd[14] >> 6; + if ((drive->card_type & SF_MMC) && CSD_STRUCTURE >= 2) { + // Get capacity from EXT_CSD register + u8 ext_csd[512]; + int ret = sdcard_pio_transfer(drive, SC_SEND_EXT_CSD, 0, ext_csd, 1); + if (ret) + return ret; + count = *(u32*)&ext_csd[212]; + } else if (!(drive->card_type & SF_MMC) && CSD_STRUCTURE >= 1) { + // High capacity SD card + u32 C_SIZE2 = csd[5] | (csd[6] << 8) | ((csd[7] & 0x3f) << 16); + count = (C_SIZE2+1) << (19-9); + } + // Fill drive struct and return + drive->drive.blksize = DISK_SECTOR_SIZE; + drive->drive.sectors = count; + return 0; +} + // Initialize an SD card static int -sdcard_card_setup(struct sdhci_s *regs) +sdcard_card_setup(struct sddrive_s *drive, int volt, int prio) { - // XXX - works on QEMU; probably wont on real hardware! - u32 param[4] = { 0x01 }; - int ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param); + struct sdhci_s *regs = drive->regs; + // Set controller to initialization clock rate + int ret = sdcard_set_frequency(regs, 400); + if (ret) + return ret; + msleep(SDHCI_CLOCK_ON_TIME); + // Reset card + u32 param[4] = { }; + ret = sdcard_pio(regs, SC_GO_IDLE_STATE, param); if (ret) return ret; - int card_type = (param[0] & SR_OCR_CCS) ? SF_SDHC : SF_SDSC; + // Let card know SDHC/SDXC is supported and confirm voltage + u32 hcs = 0, vrange = (volt >= (1<<15) ? 0x100 : 0x200) | 0xaa; + param[0] = vrange; + ret = sdcard_pio(regs, SC_SEND_IF_COND, param); + if (!ret && param[0] == vrange) + hcs = (1<<30); + // Verify SD card (instead of MMC or SDIO) + param[0] = 0x00; + ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param); + if (ret) { + // Check for MMC card + param[0] = 0x00; + ret = sdcard_pio(regs, SC_SEND_OP_COND, param); + if (ret) + return ret; + drive->card_type |= SF_MMC; + hcs = (1<<30); + } + // Init card + u32 end = timer_calc(SDHCI_POWERUP_TIMEOUT); + for (;;) { + param[0] = hcs | volt; // high-capacity support and voltage level + if (drive->card_type & SF_MMC) + ret = sdcard_pio(regs, SC_SEND_OP_COND, param); + else + ret = sdcard_pio_app(regs, SC_APP_SEND_OP_COND, param); + if (ret) + return ret; + if (param[0] & SR_OCR_NOTBUSY) + break; + if (timer_check(end)) { + warn_timeout(); + return -1; + } + msleep(5); // Avoid flooding log when debugging + } + drive->card_type |= (param[0] & SR_OCR_CCS) ? SF_HIGHCAPACITY : 0; + // Select card (get cid, set rca, get csd, select card) param[0] = 0x00; ret = sdcard_pio(regs, SC_ALL_SEND_CID, param); if (ret) return ret; - param[0] = 0x01 << 16; + u8 cid[16]; + memcpy(cid, param, sizeof(cid)); + param[0] = drive->card_type & SF_MMC ? 0x0001 << 16 : 0x00; ret = sdcard_pio(regs, SC_SEND_RELATIVE_ADDR, param); if (ret) return ret; - u16 rca = param[0] >> 16; + u16 rca = drive->card_type & SF_MMC ? 0x0001 : param[0] >> 16; + param[0] = rca << 16; + ret = sdcard_pio(regs, SC_SEND_CSD, param); + if (ret) + return ret; + u8 csd[16]; + memcpy(csd, param, sizeof(csd)); param[0] = rca << 16; ret = sdcard_pio(regs, SC_SELECT_DESELECT_CARD, param); if (ret) return ret; - return card_type; + // Set controller to data transfer clock rate + ret = sdcard_set_frequency(regs, 25000); + if (ret) + return ret; + // Register drive + ret = sdcard_get_capacity(drive, csd); + if (ret) + return ret; + char pnm[7] = {}; + int i; + for (i=0; i < (drive->card_type & SF_MMC ? 6 : 5); i++) + pnm[i] = cid[11-i]; + char *desc = znprintf(MAXDESCSIZE, "%s %s %dMiB" + , drive->card_type & SF_MMC ? "MMC drive" : "SD card" + , pnm, (u32)(drive->drive.sectors >> 11)); + dprintf(1, "Found sdcard at %p: %s\n", regs, desc); + boot_add_hd(&drive->drive, desc, prio); + return 0; } // Setup and configure an SD card controller static void -sdcard_controller_setup(void *data) +sdcard_controller_setup(struct sdhci_s *regs, int prio) { - struct pci_device *pci = data; - u16 bdf = pci->bdf; - wait_preempt(); // Avoid pci_config_readl when preempting - struct sdhci_s *regs = (void*)pci_config_readl(bdf, PCI_BASE_ADDRESS_0); - pci_config_maskw(bdf, PCI_COMMAND, 0, - PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - // Initialize controller - if (!runningOnQEMU()) - // XXX - this init logic will probably only work on qemu! + u32 present_state = readl(®s->present_state); + if (!(present_state & SP_CARD_INSERTED)) + // No card present return; + dprintf(3, "sdhci@%p ver=%x cap=%x %x\n", regs + , readw(®s->controller_version) + , readl(®s->cap_lo), readl(®s->cap_hi)); + sdcard_reset(regs, SRF_ALL); writew(®s->irq_signal, 0); - writew(®s->irq_enable, 0xffff); + writew(®s->irq_enable, 0x01ff); + writew(®s->irq_status, readw(®s->irq_status)); writew(®s->error_signal, 0); - writeb(®s->power_control, 0x0f); - writew(®s->clock_control, 0x0005); - - // Initialize card - int card_type = sdcard_card_setup(regs); - if (card_type < 0) + writew(®s->error_irq_enable, 0x01ff); + writew(®s->error_irq_status, readw(®s->error_irq_status)); + writeb(®s->timeout_control, 0x0e); // Set to max timeout + int volt = sdcard_set_power(regs); + if (volt < 0) return; - // Register drive + // Initialize card struct sddrive_s *drive = malloc_fseg(sizeof(*drive)); if (!drive) { warn_noalloc(); - return; + goto fail; } memset(drive, 0, sizeof(*drive)); drive->drive.type = DTYPE_SDCARD; - drive->drive.blksize = DISK_SECTOR_SIZE; - drive->drive.sectors = (u64)-1; // XXX drive->regs = regs; - drive->card_type = card_type; + int ret = sdcard_card_setup(drive, volt, prio); + if (ret) { + free(drive); + goto fail; + } + return; +fail: + writeb(®s->power_control, 0); + writew(®s->clock_control, 0); +} - dprintf(1, "Found SD Card at %02x:%02x.%x\n" - , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)); - char *desc = znprintf(MAXDESCSIZE, "SD Card"); // XXX - boot_add_hd(&drive->drive, desc, bootprio_find_pci_device(pci)); +static void +sdcard_pci_setup(void *data) +{ + struct pci_device *pci = data; + wait_preempt(); // Avoid pci_config_readl when preempting + // XXX - bars dependent on slot index register in pci config space + u32 regs = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0); + regs &= PCI_BASE_ADDRESS_MEM_MASK; + pci_config_maskw(pci->bdf, PCI_COMMAND, 0, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + int prio = bootprio_find_pci_device(pci); + sdcard_controller_setup((void*)regs, prio); +} + +static void +sdcard_romfile_setup(void *data) +{ + struct romfile_s *file = data; + int prio = bootprio_find_named_rom(file->name, 0); + u32 addr = romfile_loadint(file->name, 0); + dprintf(1, "Starting sdcard controller check at addr %x\n", addr); + sdcard_controller_setup((void*)addr, prio); } void @@ -311,11 +550,19 @@ sdcard_setup(void) if (!CONFIG_SDCARD) return; + struct romfile_s *file = NULL; + for (;;) { + file = romfile_findprefix("etc/sdcard", file); + if (!file) + break; + run_thread(sdcard_romfile_setup, file); + } + struct pci_device *pci; foreachpci(pci) { if (pci->class != PCI_CLASS_SYSTEM_SDHCI || pci->prog_if >= 2) // Not an SDHCI controller following SDHCI spec continue; - run_thread(sdcard_controller_setup, pci); + run_thread(sdcard_pci_setup, pci); } } diff --git a/roms/seabios/src/hw/timer.c b/roms/seabios/src/hw/timer.c index 5edc9fdbb..03d22b2f5 100644 --- a/roms/seabios/src/hw/timer.c +++ b/roms/seabios/src/hw/timer.c @@ -49,8 +49,8 @@ #define PMTIMER_HZ 3579545 // Underlying Hz of the PM Timer #define PMTIMER_TO_PIT 3 // Ratio of pmtimer rate to pit rate -u32 TimerKHz VARFSEG; -u16 TimerPort VARFSEG; +u32 TimerKHz VARFSEG = DIV_ROUND_UP(PMTIMER_HZ, 1000 * PMTIMER_TO_PIT); +u16 TimerPort VARFSEG = PORT_PIT_COUNTER0; u8 ShiftTSC VARFSEG; @@ -92,6 +92,7 @@ tsctimer_setup(void) t = (t + 1) >> 1; } TimerKHz = DIV_ROUND_UP((u32)t, 1000 * PMTIMER_TO_PIT); + TimerPort = 0; dprintf(1, "CPU Mhz=%u\n", (TimerKHz << ShiftTSC) / 1000); } @@ -100,24 +101,16 @@ tsctimer_setup(void) void timer_setup(void) { - if (CONFIG_PMTIMER && TimerPort) { - dprintf(3, "pmtimer already configured; will not calibrate TSC\n"); + if (!CONFIG_TSC_TIMER || (CONFIG_PMTIMER && TimerPort != PORT_PIT_COUNTER0)) return; - } + // Check if CPU has a timestamp counter u32 eax, ebx, ecx, edx, cpuid_features = 0; cpuid(0, &eax, &ebx, &ecx, &edx); if (eax > 0) cpuid(1, &eax, &ebx, &ecx, &cpuid_features); - - if (!(cpuid_features & CPUID_TSC)) { - TimerPort = PORT_PIT_COUNTER0; - TimerKHz = DIV_ROUND_UP(PMTIMER_HZ, 1000 * PMTIMER_TO_PIT); - dprintf(3, "386/486 class CPU. Using TSC emulation\n"); - return; - } - - tsctimer_setup(); + if (cpuid_features & CPUID_TSC) + tsctimer_setup(); } void @@ -154,7 +147,7 @@ static u32 timer_read(void) { u16 port = GET_GLOBAL(TimerPort); - if (!port) + if (CONFIG_TSC_TIMER && !port) // Read from CPU TSC return rdtscll() >> GET_GLOBAL(ShiftTSC); if (CONFIG_PMTIMER && port != PORT_PIT_COUNTER0) @@ -249,6 +242,8 @@ ticks_from_ms(u32 ms) void pit_setup(void) { + if (!CONFIG_HARDWARE_IRQ) + return; // timer0: binary count, 16bit count, mode 2 outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE); // maximum count of 0000H = 18.2Hz diff --git a/roms/seabios/src/hw/tpm_drivers.c b/roms/seabios/src/hw/tpm_drivers.c new file mode 100644 index 000000000..444eac39b --- /dev/null +++ b/roms/seabios/src/hw/tpm_drivers.c @@ -0,0 +1,291 @@ +// Implementation of a TPM driver for the TPM TIS interface +// +// Copyright (C) 2006-2011 IBM Corporation +// +// Authors: +// Stefan Berger <stefanb@linux.vnet.ibm.com> +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "config.h" // CONFIG_TPM_TIS_SHA1THRESHOLD +#include "string.h" // memcpy +#include "util.h" // msleep +#include "x86.h" // readl +#include "hw/tpm_drivers.h" // struct tpm_driver +#include "tcgbios.h" // TCG_* + +static const u32 tis_default_timeouts[4] = { + TIS_DEFAULT_TIMEOUT_A, + TIS_DEFAULT_TIMEOUT_B, + TIS_DEFAULT_TIMEOUT_C, + TIS_DEFAULT_TIMEOUT_D, +}; + +static const u32 tpm_default_durations[3] = { + TPM_DEFAULT_DURATION_SHORT, + TPM_DEFAULT_DURATION_MEDIUM, + TPM_DEFAULT_DURATION_LONG, +}; + +/* determined values */ +static u32 tpm_default_dur[3]; +static u32 tpm_default_to[4]; + + +/* if device is not there, return '0', '1' otherwise */ +static u32 tis_probe(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID)); + + if ((didvid != 0) && (didvid != 0xffffffff)) + rc = 1; + + return rc; +} + +static u32 tis_init(void) +{ + if (!CONFIG_TCGBIOS) + return 1; + + writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0); + + if (tpm_drivers[TIS_DRIVER_IDX].durations == NULL) { + u32 *durations = tpm_default_dur; + memcpy(durations, tpm_default_durations, + sizeof(tpm_default_durations)); + tpm_drivers[TIS_DRIVER_IDX].durations = durations; + } + + if (tpm_drivers[TIS_DRIVER_IDX].timeouts == NULL) { + u32 *timeouts = tpm_default_to; + memcpy(timeouts, tis_default_timeouts, + sizeof(tis_default_timeouts)); + tpm_drivers[TIS_DRIVER_IDX].timeouts = timeouts; + } + + return 1; +} + + +static void set_timeouts(u32 timeouts[4], u32 durations[3]) +{ + if (!CONFIG_TCGBIOS) + return; + + u32 *tos = tpm_drivers[TIS_DRIVER_IDX].timeouts; + u32 *dus = tpm_drivers[TIS_DRIVER_IDX].durations; + + if (tos && tos != tis_default_timeouts && timeouts) + memcpy(tos, timeouts, 4 * sizeof(u32)); + if (dus && dus != tpm_default_durations && durations) + memcpy(dus, durations, 3 * sizeof(u32)); +} + + +static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 1; + + while (time > 0) { + u8 sts = readb(TIS_REG(locty, TIS_REG_STS)); + if ((sts & mask) == expect) { + rc = 0; + break; + } + msleep(1); + time--; + } + return rc; +} + +static u32 tis_activate(u8 locty) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u8 acc; + int l; + u32 timeout_a = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_A]; + + if (!(readb(TIS_REG(locty, TIS_REG_ACCESS)) & + TIS_ACCESS_ACTIVE_LOCALITY)) { + /* release locality in use top-downwards */ + for (l = 4; l >= 0; l--) + writeb(TIS_REG(l, TIS_REG_ACCESS), + TIS_ACCESS_ACTIVE_LOCALITY); + } + + /* request access to locality */ + writeb(TIS_REG(locty, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE); + + acc = readb(TIS_REG(locty, TIS_REG_ACCESS)); + if ((acc & TIS_ACCESS_ACTIVE_LOCALITY)) { + writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY); + rc = tis_wait_sts(locty, timeout_a, + TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY); + } + + return rc; +} + +static u32 tis_find_active_locality(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u8 locty; + + for (locty = 0; locty <= 4; locty++) { + if ((readb(TIS_REG(locty, TIS_REG_ACCESS)) & + TIS_ACCESS_ACTIVE_LOCALITY)) + return locty; + } + + tis_activate(0); + + return 0; +} + +static u32 tis_ready(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u8 locty = tis_find_active_locality(); + u32 timeout_b = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_B]; + + writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY); + rc = tis_wait_sts(locty, timeout_b, + TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY); + + return rc; +} + +static u32 tis_senddata(const u8 *const data, u32 len) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u32 offset = 0; + u32 end = 0; + u16 burst = 0; + u32 ctr = 0; + u8 locty = tis_find_active_locality(); + u32 timeout_d = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_D]; + + do { + while (burst == 0 && ctr < timeout_d) { + burst = readl(TIS_REG(locty, TIS_REG_STS)) >> 8; + if (burst == 0) { + msleep(1); + ctr++; + } + } + + if (burst == 0) { + rc = TCG_RESPONSE_TIMEOUT; + break; + } + + while (1) { + writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), data[offset++]); + burst--; + + if (burst == 0 || offset == len) + break; + } + + if (offset == len) + end = 1; + } while (end == 0); + + return rc; +} + +static u32 tis_readresp(u8 *buffer, u32 *len) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u32 offset = 0; + u32 sts; + u8 locty = tis_find_active_locality(); + + while (offset < *len) { + buffer[offset] = readb(TIS_REG(locty, TIS_REG_DATA_FIFO)); + offset++; + sts = readb(TIS_REG(locty, TIS_REG_STS)); + /* data left ? */ + if ((sts & TIS_STS_DATA_AVAILABLE) == 0) + break; + } + + *len = offset; + + return rc; +} + + +static u32 tis_waitdatavalid(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u8 locty = tis_find_active_locality(); + u32 timeout_c = tpm_drivers[TIS_DRIVER_IDX].timeouts[TIS_TIMEOUT_TYPE_C]; + + if (tis_wait_sts(locty, timeout_c, TIS_STS_VALID, TIS_STS_VALID) != 0) + rc = TCG_NO_RESPONSE; + + return rc; +} + +static u32 tis_waitrespready(enum tpmDurationType to_t) +{ + if (!CONFIG_TCGBIOS) + return 0; + + u32 rc = 0; + u8 locty = tis_find_active_locality(); + u32 timeout = tpm_drivers[TIS_DRIVER_IDX].durations[to_t]; + + writeb(TIS_REG(locty ,TIS_REG_STS), TIS_STS_TPM_GO); + + if (tis_wait_sts(locty, timeout, + TIS_STS_DATA_AVAILABLE, TIS_STS_DATA_AVAILABLE) != 0) + rc = TCG_NO_RESPONSE; + + return rc; +} + + +struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = { + [TIS_DRIVER_IDX] = + { + .timeouts = NULL, + .durations = NULL, + .set_timeouts = set_timeouts, + .probe = tis_probe, + .init = tis_init, + .activate = tis_activate, + .ready = tis_ready, + .senddata = tis_senddata, + .readresp = tis_readresp, + .waitdatavalid = tis_waitdatavalid, + .waitrespready = tis_waitrespready, + .sha1threshold = 100 * 1024, + }, +}; diff --git a/roms/seabios/src/hw/tpm_drivers.h b/roms/seabios/src/hw/tpm_drivers.h new file mode 100644 index 000000000..34bb12d1c --- /dev/null +++ b/roms/seabios/src/hw/tpm_drivers.h @@ -0,0 +1,90 @@ +#ifndef TPM_DRIVERS_H +#define TPM_DRIVERS_H + +#include "types.h" // u32 + + +enum tpmDurationType { + TPM_DURATION_TYPE_SHORT = 0, + TPM_DURATION_TYPE_MEDIUM, + TPM_DURATION_TYPE_LONG, +}; + +/* low level driver implementation */ +struct tpm_driver { + u32 *timeouts; + u32 *durations; + void (*set_timeouts)(u32 timeouts[4], u32 durations[3]); + u32 (*probe)(void); + u32 (*init)(void); + u32 (*activate)(u8 locty); + u32 (*ready)(void); + u32 (*senddata)(const u8 *const data, u32 len); + u32 (*readresp)(u8 *buffer, u32 *len); + u32 (*waitdatavalid)(void); + u32 (*waitrespready)(enum tpmDurationType to_t); + /* the TPM will be used for buffers of sizes below the sha1threshold + for calculating the hash */ + u32 sha1threshold; +}; + +extern struct tpm_driver tpm_drivers[]; + + +#define TIS_DRIVER_IDX 0 +#define TPM_NUM_DRIVERS 1 + +#define TPM_INVALID_DRIVER -1 + +/* TIS driver */ +/* address of locality 0 (TIS) */ +#define TPM_TIS_BASE_ADDRESS 0xfed40000 + +#define TIS_REG(LOCTY, REG) \ + (void *)(TPM_TIS_BASE_ADDRESS + (LOCTY << 12) + REG) + +/* hardware registers */ +#define TIS_REG_ACCESS 0x0 +#define TIS_REG_INT_ENABLE 0x8 +#define TIS_REG_INT_VECTOR 0xc +#define TIS_REG_INT_STATUS 0x10 +#define TIS_REG_INTF_CAPABILITY 0x14 +#define TIS_REG_STS 0x18 +#define TIS_REG_DATA_FIFO 0x24 +#define TIS_REG_DID_VID 0xf00 +#define TIS_REG_RID 0xf04 + +#define TIS_STS_VALID (1 << 7) /* 0x80 */ +#define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */ +#define TIS_STS_TPM_GO (1 << 5) /* 0x20 */ +#define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */ +#define TIS_STS_EXPECT (1 << 3) /* 0x08 */ +#define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */ + +#define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */ +#define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */ +#define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */ +#define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */ +#define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */ +#define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */ +#define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */ + +#define SCALER 10 + +#define TIS_DEFAULT_TIMEOUT_A (750 * SCALER) +#define TIS_DEFAULT_TIMEOUT_B (2000 * SCALER) +#define TIS_DEFAULT_TIMEOUT_C (750 * SCALER) +#define TIS_DEFAULT_TIMEOUT_D (750 * SCALER) + +enum tisTimeoutType { + TIS_TIMEOUT_TYPE_A = 0, + TIS_TIMEOUT_TYPE_B, + TIS_TIMEOUT_TYPE_C, + TIS_TIMEOUT_TYPE_D, +}; + +#define TPM_DEFAULT_DURATION_SHORT (2000 * SCALER) +#define TPM_DEFAULT_DURATION_MEDIUM (20000 * SCALER) +#define TPM_DEFAULT_DURATION_LONG (60000 * SCALER) + +#endif /* TPM_DRIVERS_H */ diff --git a/roms/seabios/src/hw/usb-hid.h b/roms/seabios/src/hw/usb-hid.h index ef34e7963..fd7b8f8be 100644 --- a/roms/seabios/src/hw/usb-hid.h +++ b/roms/seabios/src/hw/usb-hid.h @@ -4,10 +4,10 @@ // usb-hid.c struct usbdevice_s; int usb_hid_setup(struct usbdevice_s *usbdev); -inline int usb_kbd_active(void); -inline int usb_kbd_command(int command, u8 *param); -inline int usb_mouse_active(void); -inline int usb_mouse_command(int command, u8 *param); +int usb_kbd_active(void); +int usb_kbd_command(int command, u8 *param); +int usb_mouse_active(void); +int usb_mouse_command(int command, u8 *param); void usb_check_event(void); diff --git a/roms/seabios/src/hw/usb-msc.c b/roms/seabios/src/hw/usb-msc.c index d90319f51..a234f13be 100644 --- a/roms/seabios/src/hw/usb-msc.c +++ b/roms/seabios/src/hw/usb-msc.c @@ -63,25 +63,27 @@ usb_msc_send(struct usbdrive_s *udrive_gf, int dir, void *buf, u32 bytes) // Low-level usb command transmit function. int -usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +usb_process_op(struct disk_op_s *op) { if (!CONFIG_USB_MSC) return 0; - dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n" - , op->drive_gf, 0, op->count, blocksize, op->buf_fl); + dprintf(16, "usb_cmd_data id=%p write=%d count=%d buf=%p\n" + , op->drive_gf, 0, op->count, op->buf_fl); struct usbdrive_s *udrive_gf = container_of( op->drive_gf, struct usbdrive_s, drive); // Setup command block wrapper. - u32 bytes = blocksize * op->count; struct cbw_s cbw; memset(&cbw, 0, sizeof(cbw)); - memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE); + int blocksize = scsi_fill_cmd(op, cbw.CBWCB, USB_CDB_SIZE); + if (blocksize < 0) + return default_process_op(op); + u32 bytes = blocksize * op->count; cbw.dCBWSignature = CBW_SIGNATURE; cbw.dCBWTag = 999; // XXX cbw.dCBWDataTransferLength = bytes; - cbw.bmCBWFlags = cdb_is_read(cdbcmd, blocksize) ? USB_DIR_IN : USB_DIR_OUT; + cbw.bmCBWFlags = scsi_is_read(op) ? USB_DIR_IN : USB_DIR_OUT; cbw.bCBWLUN = GET_GLOBALFLAT(udrive_gf->lun); cbw.bCBWCBLength = USB_CDB_SIZE; diff --git a/roms/seabios/src/hw/usb-msc.h b/roms/seabios/src/hw/usb-msc.h index c40d75556..ff3c38038 100644 --- a/roms/seabios/src/hw/usb-msc.h +++ b/roms/seabios/src/hw/usb-msc.h @@ -3,7 +3,7 @@ // usb-msc.c struct disk_op_s; -int usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +int usb_process_op(struct disk_op_s *op); struct usbdevice_s; int usb_msc_setup(struct usbdevice_s *usbdev); diff --git a/roms/seabios/src/hw/usb-uas.c b/roms/seabios/src/hw/usb-uas.c index 6ef8d0912..10e38454a 100644 --- a/roms/seabios/src/hw/usb-uas.c +++ b/roms/seabios/src/hw/usb-uas.c @@ -91,7 +91,7 @@ struct uasdrive_s { }; int -uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +uas_process_op(struct disk_op_s *op) { if (!CONFIG_USB_UAS) return DISK_RET_EBADTRACK; @@ -104,7 +104,9 @@ uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) ui.hdr.id = UAS_UI_COMMAND; ui.hdr.tag = 0xdead; ui.command.lun[1] = GET_GLOBALFLAT(drive_gf->lun); - memcpy(ui.command.cdb, cdbcmd, sizeof(ui.command.cdb)); + int blocksize = scsi_fill_cmd(op, ui.command.cdb, sizeof(ui.command.cdb)); + if (blocksize < 0) + return default_process_op(op); int ret = usb_send_bulk(GET_GLOBALFLAT(drive_gf->command), USB_DIR_OUT, MAKE_FLATPTR(GET_SEG(SS), &ui), sizeof(ui.hdr) + sizeof(ui.command)); diff --git a/roms/seabios/src/hw/usb-uas.h b/roms/seabios/src/hw/usb-uas.h index ad91c5f60..8b2f810e9 100644 --- a/roms/seabios/src/hw/usb-uas.h +++ b/roms/seabios/src/hw/usb-uas.h @@ -2,7 +2,7 @@ #define __USB_UAS_H struct disk_op_s; -int uas_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +int uas_process_op(struct disk_op_s *op); struct usbdevice_s; int usb_uas_setup(struct usbdevice_s *usbdev); diff --git a/roms/seabios/src/hw/usb-xhci.c b/roms/seabios/src/hw/usb-xhci.c index fd58334dc..654febaad 100644 --- a/roms/seabios/src/hw/usb-xhci.c +++ b/roms/seabios/src/hw/usb-xhci.c @@ -350,26 +350,41 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port) { struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb); u32 portsc = readl(&xhci->pr[port].portsc); - int rc; + if (!(portsc & XHCI_PORTSC_CCS)) + // Device no longer connected?! + return -1; switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) { case PLS_U0: - rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)]; + // A USB3 port - controller automatically performs reset break; case PLS_POLLING: + // A USB2 port - perform device reset xhci_print_port_state(3, __func__, port, portsc); - portsc |= XHCI_PORTSC_PR; - writel(&xhci->pr[port].portsc, portsc); - if (wait_bit(&xhci->pr[port].portsc, XHCI_PORTSC_PED, XHCI_PORTSC_PED, 100) != 0) - return -1; - portsc = readl(&xhci->pr[port].portsc); - rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)]; + writel(&xhci->pr[port].portsc, portsc | XHCI_PORTSC_PR); break; default: - rc = -1; - break; + return -1; } + // Wait for device to complete reset and be enabled + u32 end = timer_calc(100); + for (;;) { + portsc = readl(&xhci->pr[port].portsc); + if (!(portsc & XHCI_PORTSC_CCS)) + // Device disconnected during reset + return -1; + if (portsc & XHCI_PORTSC_PED) + // Reset complete + break; + if (timer_check(end)) { + warn_timeout(); + return -1; + } + yield(); + } + + int rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)]; xhci_print_port_state(1, "XHCI", port, portsc); return rc; } @@ -465,7 +480,7 @@ configure_xhci(void *data) xhci->evts->cs = 1; reg = readl(&xhci->caps->hcsparams2); - u32 spb = reg >> 27; + u32 spb = (reg >> 21 & 0x1f) << 5 | reg >> 27; if (spb) { dprintf(3, "%s: setup %d scratch pad buffers\n", __func__, spb); u64 *spba = memalign_high(64, sizeof(*spba) * spb); @@ -921,8 +936,14 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev usb_desc2pipe(&pipe->pipe, usbdev, epdesc); pipe->epid = epid; pipe->reqs.cs = 1; - if (eptype == USB_ENDPOINT_XFER_INT) + if (eptype == USB_ENDPOINT_XFER_INT) { pipe->buf = malloc_high(pipe->pipe.maxpacket); + if (!pipe->buf) { + warn_noalloc(); + free(pipe); + return NULL; + } + } // Allocate input context and initialize endpoint info. struct xhci_inctx *in = xhci_alloc_inctx(usbdev, epid); @@ -988,6 +1009,7 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev return &pipe->pipe; fail: + free(pipe->buf); free(pipe); free(in); return NULL; diff --git a/roms/seabios/src/hw/usb.c b/roms/seabios/src/hw/usb.c index 1b4ea8bed..e46092c63 100644 --- a/roms/seabios/src/hw/usb.c +++ b/roms/seabios/src/hw/usb.c @@ -79,9 +79,8 @@ usb_poll_intr(struct usb_pipe *pipe_fl, void *data) case USB_TYPE_EHCI: return ehci_poll_intr(pipe_fl, data); case USB_TYPE_XHCI: ; - extern void _cfunc32flat_xhci_poll_intr(void); - return call32_params(_cfunc32flat_xhci_poll_intr, (u32)pipe_fl - , (u32)MAKE_FLATPTR(GET_SEG(SS), (u32)data), 0, -1); + return call32_params(xhci_poll_intr, pipe_fl + , MAKE_FLATPTR(GET_SEG(SS), data), 0, -1); } } @@ -249,8 +248,10 @@ get_device_config(struct usb_pipe *pipe) return NULL; void *config = malloc_tmphigh(cfg.wTotalLength); - if (!config) + if (!config) { + warn_noalloc(); return NULL; + } req.wLength = cfg.wTotalLength; ret = usb_send_default_control(pipe, &req, config); if (ret) { diff --git a/roms/seabios/src/hw/virtio-blk.c b/roms/seabios/src/hw/virtio-blk.c index e2dbd3c94..20a79ebba 100644 --- a/roms/seabios/src/hw/virtio-blk.c +++ b/roms/seabios/src/hw/virtio-blk.c @@ -25,7 +25,7 @@ struct virtiodrive_s { struct drive_s drive; struct vring_virtqueue *vq; - u16 ioaddr; + struct vp_device vp; }; static int @@ -33,7 +33,7 @@ virtio_blk_op(struct disk_op_s *op, int write) { struct virtiodrive_s *vdrive_gf = container_of(op->drive_gf, struct virtiodrive_s, drive); - struct vring_virtqueue *vq = GET_GLOBALFLAT(vdrive_gf->vq); + struct vring_virtqueue *vq = vdrive_gf->vq; struct virtio_blk_outhdr hdr = { .type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN, .ioprio = 0, @@ -42,15 +42,15 @@ virtio_blk_op(struct disk_op_s *op, int write) u8 status = VIRTIO_BLK_S_UNSUPP; struct vring_list sg[] = { { - .addr = MAKE_FLATPTR(GET_SEG(SS), &hdr), + .addr = (void*)(&hdr), .length = sizeof(hdr), }, { .addr = op->buf_fl, - .length = GET_GLOBALFLAT(vdrive_gf->drive.blksize) * op->count, + .length = vdrive_gf->drive.blksize * op->count, }, { - .addr = MAKE_FLATPTR(GET_SEG(SS), &status), + .addr = (void*)(&status), .length = sizeof(status), }, }; @@ -60,7 +60,7 @@ virtio_blk_op(struct disk_op_s *op, int write) vring_add_buf(vq, sg, 2, 1, 0, 0); else vring_add_buf(vq, sg, 1, 2, 0, 0); - vring_kick(GET_GLOBALFLAT(vdrive_gf->ioaddr), vq, 1); + vring_kick(&vdrive_gf->vp, vq, 1); /* Wait for reply */ while (!vring_more_used(vq)) @@ -72,13 +72,13 @@ virtio_blk_op(struct disk_op_s *op, int write) /* Clear interrupt status register. Avoid leaving interrupts stuck if * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. */ - vp_get_isr(GET_GLOBALFLAT(vdrive_gf->ioaddr)); + vp_get_isr(&vdrive_gf->vp); return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK; } int -process_virtio_blk_op(struct disk_op_s *op) +virtio_blk_process_op(struct disk_op_s *op) { if (! CONFIG_VIRTIO_BLK) return 0; @@ -87,14 +87,8 @@ process_virtio_blk_op(struct disk_op_s *op) return virtio_blk_op(op, 0); case CMD_WRITE: return virtio_blk_op(op, 1); - case CMD_FORMAT: - case CMD_RESET: - case CMD_ISREADY: - case CMD_VERIFY: - case CMD_SEEK: - return DISK_RET_SUCCESS; default: - return DISK_RET_EPARAM; + return default_process_op(op); } } @@ -102,6 +96,7 @@ static void init_virtio_blk(struct pci_device *pci) { u16 bdf = pci->bdf; + u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER; dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); struct virtiodrive_s *vdrive = malloc_fseg(sizeof(*vdrive)); @@ -113,47 +108,93 @@ init_virtio_blk(struct pci_device *pci) vdrive->drive.type = DTYPE_VIRTIO_BLK; vdrive->drive.cntl_id = bdf; - u16 ioaddr = vp_init_simple(bdf); - vdrive->ioaddr = ioaddr; - if (vp_find_vq(ioaddr, 0, &vdrive->vq) < 0 ) { + vp_init_simple(&vdrive->vp, pci); + if (vp_find_vq(&vdrive->vp, 0, &vdrive->vq) < 0 ) { dprintf(1, "fail to find vq for virtio-blk %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); goto fail; } - struct virtio_blk_config cfg; - vp_get(ioaddr, 0, &cfg, sizeof(cfg)); - - u32 f = vp_get_features(ioaddr); - vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ? - cfg.blk_size : DISK_SECTOR_SIZE; - - vdrive->drive.sectors = cfg.capacity; - dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n", - pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), - vdrive->drive.blksize, (u32)vdrive->drive.sectors); - - if (vdrive->drive.blksize != DISK_SECTOR_SIZE) { - dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + if (vdrive->vp.use_modern) { + struct vp_device *vp = &vdrive->vp; + u64 features = vp_get_features(vp); + u64 version1 = 1ull << VIRTIO_F_VERSION_1; + u64 blk_size = 1ull << VIRTIO_BLK_F_BLK_SIZE; + if (!(features & version1)) { + dprintf(1, "modern device without virtio_1 feature bit: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + } + + features = features & (version1 | blk_size); + vp_set_features(vp, features); + status |= VIRTIO_CONFIG_S_FEATURES_OK; + vp_set_status(vp, status); + if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) { + dprintf(1, "device didn't accept features: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + } + + vdrive->drive.sectors = + vp_read(&vp->device, struct virtio_blk_config, capacity); + if (features & blk_size) { + vdrive->drive.blksize = + vp_read(&vp->device, struct virtio_blk_config, blk_size); + } else { + vdrive->drive.blksize = DISK_SECTOR_SIZE; + } + if (vdrive->drive.blksize != DISK_SECTOR_SIZE) { + dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive->drive.blksize); + goto fail; + } + dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), - vdrive->drive.blksize); - goto fail; + vdrive->drive.blksize, (u32)vdrive->drive.sectors); + + vdrive->drive.pchs.cylinder = + vp_read(&vp->device, struct virtio_blk_config, cylinders); + vdrive->drive.pchs.head = + vp_read(&vp->device, struct virtio_blk_config, heads); + vdrive->drive.pchs.sector = + vp_read(&vp->device, struct virtio_blk_config, sectors); + } else { + struct virtio_blk_config cfg; + vp_get_legacy(&vdrive->vp, 0, &cfg, sizeof(cfg)); + + u64 f = vp_get_features(&vdrive->vp); + vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ? + cfg.blk_size : DISK_SECTOR_SIZE; + + vdrive->drive.sectors = cfg.capacity; + dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive->drive.blksize, (u32)vdrive->drive.sectors); + + if (vdrive->drive.blksize != DISK_SECTOR_SIZE) { + dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + vdrive->drive.blksize); + goto fail; + } + vdrive->drive.pchs.cylinder = cfg.cylinders; + vdrive->drive.pchs.head = cfg.heads; + vdrive->drive.pchs.sector = cfg.sectors; } - vdrive->drive.pchs.cylinder = cfg.cylinders; - vdrive->drive.pchs.head = cfg.heads; - vdrive->drive.pchs.sector = cfg.sectors; char *desc = znprintf(MAXDESCSIZE, "Virtio disk PCI:%x:%x", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); boot_add_hd(&vdrive->drive, desc, bootprio_find_pci_device(pci)); - vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); + status |= VIRTIO_CONFIG_S_DRIVER_OK; + vp_set_status(&vdrive->vp, status); return; fail: - vp_reset(ioaddr); + vp_reset(&vdrive->vp); free(vdrive->vq); free(vdrive); } @@ -169,8 +210,9 @@ virtio_blk_setup(void) struct pci_device *pci; foreachpci(pci) { - if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET - || pci->device != PCI_DEVICE_ID_VIRTIO_BLK) + if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET || + (pci->device != PCI_DEVICE_ID_VIRTIO_BLK_09 && + pci->device != PCI_DEVICE_ID_VIRTIO_BLK_10)) continue; init_virtio_blk(pci); } diff --git a/roms/seabios/src/hw/virtio-blk.h b/roms/seabios/src/hw/virtio-blk.h index b233c744b..157bed627 100644 --- a/roms/seabios/src/hw/virtio-blk.h +++ b/roms/seabios/src/hw/virtio-blk.h @@ -37,7 +37,7 @@ struct virtio_blk_outhdr { #define VIRTIO_BLK_S_UNSUPP 2 struct disk_op_s; -int process_virtio_blk_op(struct disk_op_s *op); +int virtio_blk_process_op(struct disk_op_s *op); void virtio_blk_setup(void); #endif /* _VIRTIO_BLK_H */ diff --git a/roms/seabios/src/hw/virtio-pci.c b/roms/seabios/src/hw/virtio-pci.c index b9b3ab1e3..6df519489 100644 --- a/roms/seabios/src/hw/virtio-pci.c +++ b/roms/seabios/src/hw/virtio-pci.c @@ -24,47 +24,153 @@ #include "virtio-pci.h" #include "virtio-ring.h" -int vp_find_vq(unsigned int ioaddr, int queue_index, +u64 vp_get_features(struct vp_device *vp) +{ + u32 f0, f1; + + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, device_feature_select, 0); + f0 = vp_read(&vp->common, virtio_pci_common_cfg, device_feature); + vp_write(&vp->common, virtio_pci_common_cfg, device_feature_select, 1); + f1 = vp_read(&vp->common, virtio_pci_common_cfg, device_feature); + } else { + f0 = vp_read(&vp->legacy, virtio_pci_legacy, host_features); + f1 = 0; + } + return ((u64)f1 << 32) | f0; +} + +void vp_set_features(struct vp_device *vp, u64 features) +{ + u32 f0, f1; + + f0 = features; + f1 = features >> 32; + + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, guest_feature_select, 0); + vp_write(&vp->common, virtio_pci_common_cfg, guest_feature, f0); + vp_write(&vp->common, virtio_pci_common_cfg, guest_feature_select, 1); + vp_write(&vp->common, virtio_pci_common_cfg, guest_feature, f1); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, guest_features, f0); + } +} + +u8 vp_get_status(struct vp_device *vp) +{ + if (vp->use_modern) { + return vp_read(&vp->common, virtio_pci_common_cfg, device_status); + } else { + return vp_read(&vp->legacy, virtio_pci_legacy, status); + } +} + +void vp_set_status(struct vp_device *vp, u8 status) +{ + if (status == 0) /* reset */ + return; + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, device_status, status); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, status, status); + } +} + +u8 vp_get_isr(struct vp_device *vp) +{ + if (vp->use_modern) { + return vp_read(&vp->isr, virtio_pci_isr, isr); + } else { + return vp_read(&vp->legacy, virtio_pci_legacy, isr); + } +} + +void vp_reset(struct vp_device *vp) +{ + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, device_status, 0); + vp_read(&vp->isr, virtio_pci_isr, isr); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, status, 0); + vp_read(&vp->legacy, virtio_pci_legacy, isr); + } +} + +void vp_notify(struct vp_device *vp, struct vring_virtqueue *vq) +{ + if (vp->use_modern) { + u32 addr = vp->notify.addr + + vq->queue_notify_off * + vp->notify_off_multiplier; + if (vp->notify.is_io) { + outw(vq->queue_index, addr); + } else { + writew((void*)addr, vq->queue_index); + } + dprintf(9, "vp notify %x (%d) -- 0x%x\n", + addr, 2, vq->queue_index); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, queue_notify, vq->queue_index); + } +} + +int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq) { u16 num; ASSERT32FLAT(); - struct vring_virtqueue *vq = *p_vq = memalign_low(PAGE_SIZE, sizeof(*vq)); + struct vring_virtqueue *vq = *p_vq = memalign_high(PAGE_SIZE, sizeof(*vq)); if (!vq) { warn_noalloc(); goto fail; } memset(vq, 0, sizeof(*vq)); - /* select the queue */ - outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); + /* select the queue */ + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, queue_select, queue_index); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, queue_sel, queue_index); + } /* check if the queue is available */ - - num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM); + if (vp->use_modern) { + num = vp_read(&vp->common, virtio_pci_common_cfg, queue_size); + if (num > MAX_QUEUE_NUM) { + vp_write(&vp->common, virtio_pci_common_cfg, queue_size, + MAX_QUEUE_NUM); + num = vp_read(&vp->common, virtio_pci_common_cfg, queue_size); + } + } else { + num = vp_read(&vp->legacy, virtio_pci_legacy, queue_num); + } if (!num) { dprintf(1, "ERROR: queue size is 0\n"); goto fail; } - if (num > MAX_QUEUE_NUM) { dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM); goto fail; } /* check if the queue is already active */ - - if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) { - dprintf(1, "ERROR: queue already active\n"); - goto fail; + if (vp->use_modern) { + if (vp_read(&vp->common, virtio_pci_common_cfg, queue_enable)) { + dprintf(1, "ERROR: queue already active\n"); + goto fail; + } + } else { + if (vp_read(&vp->legacy, virtio_pci_legacy, queue_pfn)) { + dprintf(1, "ERROR: queue already active\n"); + goto fail; + } } - vq->queue_index = queue_index; /* initialize the queue */ - struct vring * vr = &vq->vring; vring_init(vr, num, (unsigned char*)&vq->queue); @@ -73,9 +179,23 @@ int vp_find_vq(unsigned int ioaddr, int queue_index, * NOTE: vr->desc is initialized by vring_init() */ - outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT, - ioaddr + VIRTIO_PCI_QUEUE_PFN); - + if (vp->use_modern) { + vp_write(&vp->common, virtio_pci_common_cfg, queue_desc_lo, + (unsigned long)virt_to_phys(vr->desc)); + vp_write(&vp->common, virtio_pci_common_cfg, queue_desc_hi, 0); + vp_write(&vp->common, virtio_pci_common_cfg, queue_avail_lo, + (unsigned long)virt_to_phys(vr->avail)); + vp_write(&vp->common, virtio_pci_common_cfg, queue_avail_hi, 0); + vp_write(&vp->common, virtio_pci_common_cfg, queue_used_lo, + (unsigned long)virt_to_phys(vr->used)); + vp_write(&vp->common, virtio_pci_common_cfg, queue_used_hi, 0); + vp_write(&vp->common, virtio_pci_common_cfg, queue_enable, 1); + vq->queue_notify_off = vp_read(&vp->common, virtio_pci_common_cfg, + queue_notify_off); + } else { + vp_write(&vp->legacy, virtio_pci_legacy, queue_pfn, + (unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT); + } return num; fail: @@ -84,14 +204,76 @@ fail: return -1; } -u16 vp_init_simple(u16 bdf) +void vp_init_simple(struct vp_device *vp, struct pci_device *pci) { - u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & - PCI_BASE_ADDRESS_IO_MASK; + u8 cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, 0); + struct vp_cap *vp_cap; + u32 addr, offset, mul; + u8 type; + + memset(vp, 0, sizeof(*vp)); + while (cap != 0) { + type = pci_config_readb(pci->bdf, cap + + offsetof(struct virtio_pci_cap, cfg_type)); + switch (type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + vp_cap = &vp->common; + break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: + vp_cap = &vp->notify; + mul = offsetof(struct virtio_pci_notify_cap, notify_off_multiplier); + vp->notify_off_multiplier = pci_config_readl(pci->bdf, cap + mul); + break; + case VIRTIO_PCI_CAP_ISR_CFG: + vp_cap = &vp->isr; + break; + case VIRTIO_PCI_CAP_DEVICE_CFG: + vp_cap = &vp->device; + break; + default: + vp_cap = NULL; + break; + } + if (vp_cap && !vp_cap->cap) { + vp_cap->cap = cap; + vp_cap->bar = pci_config_readb(pci->bdf, cap + + offsetof(struct virtio_pci_cap, bar)); + offset = pci_config_readl(pci->bdf, cap + + offsetof(struct virtio_pci_cap, offset)); + addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0 + 4 * vp_cap->bar); + if (addr & PCI_BASE_ADDRESS_SPACE_IO) { + vp_cap->is_io = 1; + addr &= PCI_BASE_ADDRESS_IO_MASK; + } else { + vp_cap->is_io = 0; + addr &= PCI_BASE_ADDRESS_MEM_MASK; + } + vp_cap->addr = addr + offset; + dprintf(3, "pci dev %x:%x virtio cap at 0x%x type %d " + "bar %d at 0x%08x off +0x%04x [%s]\n", + pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf), + vp_cap->cap, type, vp_cap->bar, addr, offset, + vp_cap->is_io ? "io" : "mmio"); + } + + cap = pci_find_capability(pci, PCI_CAP_ID_VNDR, cap); + } + + if (vp->common.cap && vp->notify.cap && vp->isr.cap && vp->device.cap) { + dprintf(1, "pci dev %x:%x using modern (1.0) virtio mode\n", + pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)); + vp->use_modern = 1; + } else { + dprintf(1, "pci dev %x:%x using legacy (0.9.5) virtio mode\n", + pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf)); + vp->legacy.bar = 0; + vp->legacy.addr = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) & + PCI_BASE_ADDRESS_IO_MASK; + vp->legacy.is_io = 1; + } - vp_reset(ioaddr); - pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); - vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | + vp_reset(vp); + pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); + vp_set_status(vp, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER ); - return ioaddr; } diff --git a/roms/seabios/src/hw/virtio-pci.h b/roms/seabios/src/hw/virtio-pci.h index bc04b039e..b11c3555e 100644 --- a/roms/seabios/src/hw/virtio-pci.h +++ b/roms/seabios/src/hw/virtio-pci.h @@ -2,104 +2,210 @@ #define _VIRTIO_PCI_H #include "x86.h" // inl - -/* A 32-bit r/o bitmask of the features supported by the host */ -#define VIRTIO_PCI_HOST_FEATURES 0 - -/* A 32-bit r/w bitmask of features activated by the guest */ -#define VIRTIO_PCI_GUEST_FEATURES 4 - -/* A 32-bit r/w PFN for the currently selected queue */ -#define VIRTIO_PCI_QUEUE_PFN 8 - -/* A 16-bit r/o queue size for the currently selected queue */ -#define VIRTIO_PCI_QUEUE_NUM 12 - -/* A 16-bit r/w queue selector */ -#define VIRTIO_PCI_QUEUE_SEL 14 - -/* A 16-bit r/w queue notifier */ -#define VIRTIO_PCI_QUEUE_NOTIFY 16 - -/* An 8-bit device status register. */ -#define VIRTIO_PCI_STATUS 18 - -/* An 8-bit r/o interrupt status register. Reading the value will return the - * current contents of the ISR and will also clear it. This is effectively - * a read-and-acknowledge. */ -#define VIRTIO_PCI_ISR 19 +#include "biosvar.h" // GET_LOWFLAT /* The bit of the ISR which indicates a device configuration change. */ #define VIRTIO_PCI_ISR_CONFIG 0x2 -/* The remaining space is defined by each driver as the per-driver - * configuration space */ -#define VIRTIO_PCI_CONFIG 20 - /* Virtio ABI version, this must match exactly */ #define VIRTIO_PCI_ABI_VERSION 0 -static inline u32 vp_get_features(unsigned int ioaddr) -{ - return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES); -} - -static inline void vp_set_features(unsigned int ioaddr, u32 features) +/* --- virtio 0.9.5 (legacy) struct --------------------------------- */ + +typedef struct virtio_pci_legacy { + u32 host_features; + u32 guest_features; + u32 queue_pfn; + u16 queue_num; + u16 queue_sel; + u16 queue_notify; + u8 status; + u8 isr; + u8 device[]; +} virtio_pci_legacy; + +/* --- virtio 1.0 (modern) structs ---------------------------------- */ + +/* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 +/* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 +/* ISR access */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 +/* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 +/* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + +/* This is the PCI capability header: */ +struct virtio_pci_cap { + u8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */ + u8 cap_next; /* Generic PCI field: next ptr. */ + u8 cap_len; /* Generic PCI field: capability length */ + u8 cfg_type; /* Identifies the structure. */ + u8 bar; /* Where to find it. */ + u8 padding[3]; /* Pad to full dword. */ + u32 offset; /* Offset within bar. */ + u32 length; /* Length of the structure, in bytes. */ +}; + +struct virtio_pci_notify_cap { + struct virtio_pci_cap cap; + u32 notify_off_multiplier; /* Multiplier for queue_notify_off. */ +}; + +typedef struct virtio_pci_common_cfg { + /* About the whole device. */ + u32 device_feature_select; /* read-write */ + u32 device_feature; /* read-only */ + u32 guest_feature_select; /* read-write */ + u32 guest_feature; /* read-write */ + u16 msix_config; /* read-write */ + u16 num_queues; /* read-only */ + u8 device_status; /* read-write */ + u8 config_generation; /* read-only */ + + /* About a specific virtqueue. */ + u16 queue_select; /* read-write */ + u16 queue_size; /* read-write, power of 2. */ + u16 queue_msix_vector; /* read-write */ + u16 queue_enable; /* read-write */ + u16 queue_notify_off; /* read-only */ + u32 queue_desc_lo; /* read-write */ + u32 queue_desc_hi; /* read-write */ + u32 queue_avail_lo; /* read-write */ + u32 queue_avail_hi; /* read-write */ + u32 queue_used_lo; /* read-write */ + u32 queue_used_hi; /* read-write */ +} virtio_pci_common_cfg; + +typedef struct virtio_pci_isr { + u8 isr; +} virtio_pci_isr; + +/* --- driver structs ----------------------------------------------- */ + +struct vp_cap { + u32 addr; + u8 cap; + u8 bar; + u8 is_io; +}; + +struct vp_device { + struct vp_cap common, notify, isr, device, legacy; + u32 notify_off_multiplier; + u8 use_modern; +}; + +static inline u64 _vp_read(struct vp_cap *cap, u32 offset, u8 size) { - outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES); + u32 addr = cap->addr + offset; + u64 var; + + if (cap->is_io) { + switch (size) { + case 8: + var = inl(addr); + var |= (u64)inl(addr+4) << 32; + break; + case 4: + var = inl(addr); + break; + case 2: + var = inw(addr); + break; + case 1: + var = inb(addr); + break; + default: + var = 0; + } + } else { + switch (size) { + case 8: + var = readl((void*)addr); + var |= (u64)readl((void*)(addr+4)) << 32; + break; + case 4: + var = readl((void*)addr); + break; + case 2: + var = readw((void*)addr); + break; + case 1: + var = readb((void*)addr); + break; + default: + var = 0; + } + } + dprintf(9, "vp read %x (%d) -> 0x%llx\n", addr, size, var); + return var; } -static inline void vp_get(unsigned int ioaddr, unsigned offset, - void *buf, unsigned len) +static inline void _vp_write(struct vp_cap *cap, u32 offset, u8 size, u64 var) { - u8 *ptr = buf; - unsigned i; - - for (i = 0; i < len; i++) - ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i); + u32 addr = cap->addr + offset; + + dprintf(9, "vp write %x (%d) <- 0x%llx\n", addr, size, var); + if (cap->is_io) { + switch (size) { + case 4: + outl(var, addr); + break; + case 2: + outw(var, addr); + break; + case 1: + outb(var, addr); + break; + } + } else { + switch (size) { + case 4: + writel((void*)addr, var); + break; + case 2: + writew((void*)addr, var); + break; + case 1: + writeb((void*)addr, var); + break; + } + } } -static inline u8 vp_get_status(unsigned int ioaddr) -{ - return inb(ioaddr + VIRTIO_PCI_STATUS); -} +#define vp_read(_cap, _struct, _field) \ + _vp_read(_cap, offsetof(_struct, _field), \ + sizeof(((_struct *)0)->_field)) -static inline void vp_set_status(unsigned int ioaddr, u8 status) -{ - if (status == 0) /* reset */ - return; - outb(status, ioaddr + VIRTIO_PCI_STATUS); -} +#define vp_write(_cap, _struct, _field, _var) \ + _vp_write(_cap, offsetof(_struct, _field), \ + sizeof(((_struct *)0)->_field), _var) -static inline u8 vp_get_isr(unsigned int ioaddr) -{ - return inb(ioaddr + VIRTIO_PCI_ISR); -} +u64 vp_get_features(struct vp_device *vp); +void vp_set_features(struct vp_device *vp, u64 features); -static inline void vp_reset(unsigned int ioaddr) +static inline void vp_get_legacy(struct vp_device *vp, unsigned offset, + void *buf, unsigned len) { - outb(0, ioaddr + VIRTIO_PCI_STATUS); - (void)inb(ioaddr + VIRTIO_PCI_ISR); -} + u8 *ptr = buf; + unsigned i; -static inline void vp_notify(unsigned int ioaddr, int queue_index) -{ - outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY); + for (i = 0; i < len; i++) + ptr[i] = vp_read(&vp->legacy, virtio_pci_legacy, device[i]); } -static inline void vp_del_vq(unsigned int ioaddr, int queue_index) -{ - /* select the queue */ - - outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); - - /* deactivate the queue */ - - outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN); -} +u8 vp_get_status(struct vp_device *vp); +void vp_set_status(struct vp_device *vp, u8 status); +u8 vp_get_isr(struct vp_device *vp); +void vp_reset(struct vp_device *vp); +struct pci_device; struct vring_virtqueue; -u16 vp_init_simple(u16 bdf); -int vp_find_vq(unsigned int ioaddr, int queue_index, +void vp_init_simple(struct vp_device *vp, struct pci_device *pci); +void vp_notify(struct vp_device *vp, struct vring_virtqueue *vq); +int vp_find_vq(struct vp_device *vp, int queue_index, struct vring_virtqueue **p_vq); #endif /* _VIRTIO_PCI_H_ */ diff --git a/roms/seabios/src/hw/virtio-ring.c b/roms/seabios/src/hw/virtio-ring.c index 97e0b3487..7205a0acd 100644 --- a/roms/seabios/src/hw/virtio-ring.c +++ b/roms/seabios/src/hw/virtio-ring.c @@ -35,8 +35,8 @@ int vring_more_used(struct vring_virtqueue *vq) { - struct vring_used *used = GET_LOWFLAT(vq->vring.used); - int more = GET_LOWFLAT(vq->last_used_idx) != GET_LOWFLAT(used->idx); + struct vring_used *used = vq->vring.used; + int more = vq->last_used_idx != used->idx; /* Make sure ring reads are done after idx read above. */ smp_rmb(); return more; @@ -57,13 +57,13 @@ void vring_detach(struct vring_virtqueue *vq, unsigned int head) /* find end of given descriptor */ i = head; - while (GET_LOWFLAT(desc[i].flags) & VRING_DESC_F_NEXT) - i = GET_LOWFLAT(desc[i].next); + while (desc[i].flags & VRING_DESC_F_NEXT) + i = desc[i].next; /* link it with free list and point to it */ - SET_LOWFLAT(desc[i].next, GET_LOWFLAT(vq->free_head)); - SET_LOWFLAT(vq->free_head, head); + desc[i].next = vq->free_head; + vq->free_head = head; } /* @@ -77,22 +77,22 @@ int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len) { struct vring *vr = &vq->vring; struct vring_used_elem *elem; - struct vring_used *used = GET_LOWFLAT(vq->vring.used); + struct vring_used *used = vq->vring.used; u32 id; int ret; // BUG_ON(!vring_more_used(vq)); - elem = &used->ring[GET_LOWFLAT(vq->last_used_idx) % GET_LOWFLAT(vr->num)]; - id = GET_LOWFLAT(elem->id); + elem = &used->ring[vq->last_used_idx % vr->num]; + id = elem->id; if (len != NULL) - *len = GET_LOWFLAT(elem->len); + *len = elem->len; - ret = GET_LOWFLAT(vq->vdata[id]); + ret = vq->vdata[id]; vring_detach(vq, id); - SET_LOWFLAT(vq->last_used_idx, GET_LOWFLAT(vq->last_used_idx) + 1); + vq->last_used_idx = vq->last_used_idx + 1; return ret; } @@ -104,46 +104,45 @@ void vring_add_buf(struct vring_virtqueue *vq, { struct vring *vr = &vq->vring; int i, av, head, prev; - struct vring_desc *desc = GET_LOWFLAT(vr->desc); - struct vring_avail *avail = GET_LOWFLAT(vr->avail); + struct vring_desc *desc = vr->desc; + struct vring_avail *avail = vr->avail; BUG_ON(out + in == 0); prev = 0; - head = GET_LOWFLAT(vq->free_head); - for (i = head; out; i = GET_LOWFLAT(desc[i].next), out--) { - SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT); - SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr)); - SET_LOWFLAT(desc[i].len, list->length); + head = vq->free_head; + for (i = head; out; i = desc[i].next, out--) { + desc[i].flags = VRING_DESC_F_NEXT; + desc[i].addr = (u64)virt_to_phys(list->addr); + desc[i].len = list->length; prev = i; list++; } - for ( ; in; i = GET_LOWFLAT(desc[i].next), in--) { - SET_LOWFLAT(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE); - SET_LOWFLAT(desc[i].addr, (u64)virt_to_phys(list->addr)); - SET_LOWFLAT(desc[i].len, list->length); + for ( ; in; i = desc[i].next, in--) { + desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; + desc[i].addr = (u64)virt_to_phys(list->addr); + desc[i].len = list->length; prev = i; list++; } - SET_LOWFLAT(desc[prev].flags, - GET_LOWFLAT(desc[prev].flags) & ~VRING_DESC_F_NEXT); + desc[prev].flags = desc[prev].flags & ~VRING_DESC_F_NEXT; - SET_LOWFLAT(vq->free_head, i); + vq->free_head = i; - SET_LOWFLAT(vq->vdata[head], index); + vq->vdata[head] = index; - av = (GET_LOWFLAT(avail->idx) + num_added) % GET_LOWFLAT(vr->num); - SET_LOWFLAT(avail->ring[av], head); + av = (avail->idx + num_added) % vr->num; + avail->ring[av] = head; } -void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added) +void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added) { struct vring *vr = &vq->vring; - struct vring_avail *avail = GET_LOWFLAT(vr->avail); + struct vring_avail *avail = vr->avail; /* Make sure idx update is done after ring write. */ smp_wmb(); - SET_LOWFLAT(avail->idx, GET_LOWFLAT(avail->idx) + num_added); + avail->idx = avail->idx + num_added; - vp_notify(ioaddr, GET_LOWFLAT(vq->queue_index)); + vp_notify(vp, vq); } diff --git a/roms/seabios/src/hw/virtio-ring.h b/roms/seabios/src/hw/virtio-ring.h index b7a7aafb2..7665fd54b 100644 --- a/roms/seabios/src/hw/virtio-ring.h +++ b/roms/seabios/src/hw/virtio-ring.h @@ -4,15 +4,6 @@ #include "types.h" // u64 #include "memmap.h" // PAGE_SIZE -#define PAGE_SHIFT 12 -#define PAGE_MASK (PAGE_SIZE-1) - -#define virt_to_phys(v) (unsigned long)(v) -#define phys_to_virt(p) (void*)(p) -/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */ -#define smp_rmb() barrier() -#define smp_wmb() barrier() - /* Status byte for guest to report progress, and synchronize features. */ /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ #define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 @@ -20,9 +11,14 @@ #define VIRTIO_CONFIG_S_DRIVER 2 /* Driver has used its parts of the config, and is happy */ #define VIRTIO_CONFIG_S_DRIVER_OK 4 +/* Driver has finished configuring features */ +#define VIRTIO_CONFIG_S_FEATURES_OK 8 /* We've given up on this device. */ #define VIRTIO_CONFIG_S_FAILED 0x80 +/* v1.0 compliant. */ +#define VIRTIO_F_VERSION_1 32 + #define MAX_QUEUE_NUM (128) #define VRING_DESC_F_NEXT 1 @@ -68,10 +64,9 @@ struct vring { }; #define vring_size(num) \ - (((((sizeof(struct vring_desc) * num) + \ - (sizeof(struct vring_avail) + sizeof(u16) * num)) \ - + PAGE_MASK) & ~PAGE_MASK) + \ - (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num)) + (ALIGN(sizeof(struct vring_desc) * num + sizeof(struct vring_avail) \ + + sizeof(u16) * num, PAGE_SIZE) \ + + sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num) typedef unsigned char virtio_queue_t[vring_size(MAX_QUEUE_NUM)]; @@ -83,6 +78,7 @@ struct vring_virtqueue { u16 vdata[MAX_QUEUE_NUM]; /* PCI */ int queue_index; + int queue_notify_off; }; struct vring_list { @@ -90,42 +86,35 @@ struct vring_list { unsigned int length; }; -static inline void vring_init(struct vring *vr, - unsigned int num, unsigned char *queue) +static inline void +vring_init(struct vring *vr, unsigned int num, unsigned char *queue) { - unsigned int i; - unsigned long pa; - ASSERT32FLAT(); vr->num = num; /* physical address of desc must be page aligned */ - - pa = virt_to_phys(queue); - pa = (pa + PAGE_MASK) & ~PAGE_MASK; - vr->desc = phys_to_virt(pa); + vr->desc = (void*)ALIGN((u32)queue, PAGE_SIZE); vr->avail = (struct vring_avail *)&vr->desc[num]; /* disable interrupts */ vr->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; /* physical address of used must be page aligned */ + vr->used = (void*)ALIGN((u32)&vr->avail->ring[num], PAGE_SIZE); - pa = virt_to_phys(&vr->avail->ring[num]); - pa = (pa + PAGE_MASK) & ~PAGE_MASK; - vr->used = phys_to_virt(pa); - + int i; for (i = 0; i < num - 1; i++) - vr->desc[i].next = i + 1; + vr->desc[i].next = i + 1; vr->desc[i].next = 0; } +struct vp_device; int vring_more_used(struct vring_virtqueue *vq); void vring_detach(struct vring_virtqueue *vq, unsigned int head); int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len); void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[], unsigned int out, unsigned int in, int index, int num_added); -void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added); +void vring_kick(struct vp_device *vp, struct vring_virtqueue *vq, int num_added); #endif /* _VIRTIO_RING_H_ */ diff --git a/roms/seabios/src/hw/virtio-scsi.c b/roms/seabios/src/hw/virtio-scsi.c index 8f966875b..80afd04ca 100644 --- a/roms/seabios/src/hw/virtio-scsi.c +++ b/roms/seabios/src/hw/virtio-scsi.c @@ -27,35 +27,42 @@ struct virtio_lun_s { struct drive_s drive; struct pci_device *pci; struct vring_virtqueue *vq; - u16 ioaddr; + struct vp_device *vp; u16 target; u16 lun; }; -static int -virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, - void *cdbcmd, u16 target, u16 lun, u16 blocksize) +int +virtio_scsi_process_op(struct disk_op_s *op) { + if (! CONFIG_VIRTIO_SCSI) + return 0; + struct virtio_lun_s *vlun = + container_of(op->drive_gf, struct virtio_lun_s, drive); + struct vp_device *vp = vlun->vp; + struct vring_virtqueue *vq = vlun->vq; struct virtio_scsi_req_cmd req; struct virtio_scsi_resp_cmd resp; struct vring_list sg[3]; memset(&req, 0, sizeof(req)); + int blocksize = scsi_fill_cmd(op, req.cdb, 16); + if (blocksize < 0) + return default_process_op(op); req.lun[0] = 1; - req.lun[1] = target; - req.lun[2] = (lun >> 8) | 0x40; - req.lun[3] = (lun & 0xff); - memcpy(req.cdb, cdbcmd, 16); + req.lun[1] = vlun->target; + req.lun[2] = (vlun->lun >> 8) | 0x40; + req.lun[3] = (vlun->lun & 0xff); u32 len = op->count * blocksize; - int datain = cdb_is_read(cdbcmd, blocksize); + int datain = scsi_is_read(op); int in_num = (datain ? 2 : 1); int out_num = (len ? 3 : 2) - in_num; - sg[0].addr = MAKE_FLATPTR(GET_SEG(SS), &req); + sg[0].addr = (void*)(&req); sg[0].length = sizeof(req); - sg[out_num].addr = MAKE_FLATPTR(GET_SEG(SS), &resp); + sg[out_num].addr = (void*)(&resp); sg[out_num].length = sizeof(resp); if (len) { @@ -66,7 +73,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, /* Add to virtqueue and kick host */ vring_add_buf(vq, sg, out_num, in_num, 0, 0); - vring_kick(ioaddr, vq, 1); + vring_kick(vp, vq, 1); /* Wait for reply */ while (!vring_more_used(vq)) @@ -78,7 +85,7 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, /* Clear interrupt status register. Avoid leaving interrupts stuck if * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. */ - vp_get_isr(ioaddr); + vp_get_isr(vp); if (resp.response == VIRTIO_SCSI_S_OK && resp.status == 0) { return DISK_RET_SUCCESS; @@ -86,21 +93,8 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, return DISK_RET_EBADTRACK; } -int -virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) -{ - struct virtio_lun_s *vlun_gf = - container_of(op->drive_gf, struct virtio_lun_s, drive); - - return virtio_scsi_cmd(GET_GLOBALFLAT(vlun_gf->ioaddr), - GET_GLOBALFLAT(vlun_gf->vq), op, cdbcmd, - GET_GLOBALFLAT(vlun_gf->target), - GET_GLOBALFLAT(vlun_gf->lun), - blocksize); -} - static int -virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr, +virtio_scsi_add_lun(struct pci_device *pci, struct vp_device *vp, struct vring_virtqueue *vq, u16 target, u16 lun) { struct virtio_lun_s *vlun = malloc_fseg(sizeof(*vlun)); @@ -112,7 +106,7 @@ virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr, vlun->drive.type = DTYPE_VIRTIO_SCSI; vlun->drive.cntl_id = pci->bdf; vlun->pci = pci; - vlun->ioaddr = ioaddr; + vlun->vp = vp; vlun->vq = vq; vlun->target = target; vlun->lun = lun; @@ -129,11 +123,11 @@ fail: } static int -virtio_scsi_scan_target(struct pci_device *pci, u16 ioaddr, +virtio_scsi_scan_target(struct pci_device *pci, struct vp_device *vp, struct vring_virtqueue *vq, u16 target) { /* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */ - int ret = virtio_scsi_add_lun(pci, ioaddr, vq, target, 0); + int ret = virtio_scsi_add_lun(pci, vp, vq, target, 0); return ret < 0 ? 0 : 1; } @@ -144,19 +138,45 @@ init_virtio_scsi(struct pci_device *pci) dprintf(1, "found virtio-scsi at %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); struct vring_virtqueue *vq = NULL; - u16 ioaddr = vp_init_simple(bdf); - if (vp_find_vq(ioaddr, 2, &vq) < 0 ) { + struct vp_device *vp = malloc_high(sizeof(*vp)); + if (!vp) { + warn_noalloc(); + return; + } + vp_init_simple(vp, pci); + u8 status = VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER; + + if (vp->use_modern) { + u64 features = vp_get_features(vp); + u64 version1 = 1ull << VIRTIO_F_VERSION_1; + if (!(features & version1)) { + dprintf(1, "modern device without virtio_1 feature bit: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + } + + vp_set_features(vp, version1); + status |= VIRTIO_CONFIG_S_FEATURES_OK; + vp_set_status(vp, status); + if (!(vp_get_status(vp) & VIRTIO_CONFIG_S_FEATURES_OK)) { + dprintf(1, "device didn't accept features: %x:%x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); + goto fail; + } + } + + if (vp_find_vq(vp, 2, &vq) < 0 ) { dprintf(1, "fail to find vq for virtio-scsi %x:%x\n", pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); goto fail; } - vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); + status |= VIRTIO_CONFIG_S_DRIVER_OK; + vp_set_status(vp, status); int i, tot; for (tot = 0, i = 0; i < 256; i++) - tot += virtio_scsi_scan_target(pci, ioaddr, vq, i); + tot += virtio_scsi_scan_target(pci, vp, vq, i); if (!tot) goto fail; @@ -164,7 +184,8 @@ init_virtio_scsi(struct pci_device *pci) return; fail: - vp_reset(ioaddr); + vp_reset(vp); + free(vp); free(vq); } @@ -179,8 +200,9 @@ virtio_scsi_setup(void) struct pci_device *pci; foreachpci(pci) { - if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET - || pci->device != PCI_DEVICE_ID_VIRTIO_SCSI) + if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET || + (pci->device != PCI_DEVICE_ID_VIRTIO_SCSI_09 && + pci->device != PCI_DEVICE_ID_VIRTIO_SCSI_10)) continue; init_virtio_scsi(pci); } diff --git a/roms/seabios/src/hw/virtio-scsi.h b/roms/seabios/src/hw/virtio-scsi.h index 96c3701d2..7532cc98e 100644 --- a/roms/seabios/src/hw/virtio-scsi.h +++ b/roms/seabios/src/hw/virtio-scsi.h @@ -41,7 +41,7 @@ struct virtio_scsi_resp_cmd { #define VIRTIO_SCSI_S_OK 0 struct disk_op_s; -int virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); +int virtio_scsi_process_op(struct disk_op_s *op); void virtio_scsi_setup(void); #endif /* _VIRTIO_SCSI_H */ diff --git a/roms/seabios/src/list.h b/roms/seabios/src/list.h index de656b9d6..94512e306 100644 --- a/roms/seabios/src/list.h +++ b/roms/seabios/src/list.h @@ -61,6 +61,16 @@ hlist_add_after(struct hlist_node *n, struct hlist_node *prev) hlist_add(n, &prev->next); } +static inline void +hlist_replace(struct hlist_node *old, struct hlist_node *new) +{ + new->next = old->next; + if (new->next) + new->next->pprev = &new->next; + new->pprev = old->pprev; + *new->pprev = new; +} + #define hlist_for_each_entry(pos, head, member) \ for (pos = container_of((head)->first, typeof(*pos), member) \ ; pos != container_of(NULL, typeof(*pos), member) \ diff --git a/roms/seabios/src/malloc.c b/roms/seabios/src/malloc.c index c4cb17149..3733855ca 100644 --- a/roms/seabios/src/malloc.c +++ b/roms/seabios/src/malloc.c @@ -6,9 +6,10 @@ #include "biosvar.h" // GET_BDA #include "config.h" // BUILD_BIOS_ADDR +#include "e820map.h" // struct e820entry #include "list.h" // hlist_node #include "malloc.h" // _malloc -#include "memmap.h" // struct e820entry +#include "memmap.h" // PAGE_SIZE #include "output.h" // dprintf #include "stacks.h" // wait_preempt #include "std/optionrom.h" // OPTION_ROM_ALIGN @@ -17,7 +18,7 @@ // Information on a reserved area. struct allocinfo_s { struct hlist_node node; - void *data, *dataend, *allocend; + u32 range_start, range_end, alloc_size; }; // Information on a tracked memory allocation. @@ -46,98 +47,106 @@ static struct zone_s *Zones[] VARVERIFY32INIT = { ****************************************************************/ // Find and reserve space from a given zone -static void * -allocSpace(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill) +static u32 +alloc_new(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill) { struct allocinfo_s *info; hlist_for_each_entry(info, &zone->head, node) { - void *dataend = info->dataend; - void *allocend = info->allocend; - void *newallocend = (void*)ALIGN_DOWN((u32)allocend - size, align); - if (newallocend >= dataend && newallocend <= allocend) { + u32 alloc_end = info->range_start + info->alloc_size; + u32 range_end = info->range_end; + u32 new_range_end = ALIGN_DOWN(range_end - size, align); + if (new_range_end >= alloc_end && new_range_end <= range_end) { // Found space - now reserve it. - if (!fill) - fill = newallocend; - fill->data = newallocend; - fill->dataend = newallocend + size; - fill->allocend = allocend; + fill->range_start = new_range_end; + fill->range_end = range_end; + fill->alloc_size = size; - info->allocend = newallocend; + info->range_end = new_range_end; hlist_add_before(&fill->node, &info->node); - return newallocend; + return new_range_end; } } - return NULL; + return 0; } -// Release space allocated with allocSpace() -static void -freeSpace(struct allocinfo_s *info) +// Reserve space for a 'struct allocdetail_s' and fill +static struct allocdetail_s * +alloc_new_detail(struct allocdetail_s *temp) { - struct allocinfo_s *next = container_of_or_null( - info->node.next, struct allocinfo_s, node); - if (next && next->allocend == info->data) - next->allocend = info->allocend; - hlist_del(&info->node); + u32 detail_addr = alloc_new(&ZoneTmpHigh, sizeof(struct allocdetail_s) + , MALLOC_MIN_ALIGN, &temp->detailinfo); + if (!detail_addr) { + detail_addr = alloc_new(&ZoneTmpLow, sizeof(struct allocdetail_s) + , MALLOC_MIN_ALIGN, &temp->detailinfo); + if (!detail_addr) { + warn_noalloc(); + return NULL; + } + } + struct allocdetail_s *detail = memremap(detail_addr, sizeof(*detail)); + + // Fill final 'detail' allocation from data in 'temp' + memcpy(detail, temp, sizeof(*detail)); + hlist_replace(&temp->detailinfo.node, &detail->detailinfo.node); + hlist_replace(&temp->datainfo.node, &detail->datainfo.node); + return detail; } // Add new memory to a zone static void -addSpace(struct zone_s *zone, void *start, void *end) +alloc_add(struct zone_s *zone, u32 start, u32 end) { // Find position to add space struct allocinfo_s *info; struct hlist_node **pprev; hlist_for_each_entry_pprev(info, pprev, &zone->head, node) { - if (info->data < start) + if (info->range_start < start) break; } // Add space using temporary allocation info. struct allocdetail_s tempdetail; - tempdetail.datainfo.data = tempdetail.datainfo.dataend = start; - tempdetail.datainfo.allocend = end; + tempdetail.handle = MALLOC_DEFAULT_HANDLE; + tempdetail.datainfo.range_start = start; + tempdetail.datainfo.range_end = end; + tempdetail.datainfo.alloc_size = 0; hlist_add(&tempdetail.datainfo.node, pprev); // Allocate final allocation info. - struct allocdetail_s *detail = allocSpace( - &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL); - if (!detail) { - detail = allocSpace(&ZoneTmpLow, sizeof(*detail) - , MALLOC_MIN_ALIGN, NULL); - if (!detail) { - hlist_del(&tempdetail.datainfo.node); - warn_noalloc(); - return; - } - } + struct allocdetail_s *detail = alloc_new_detail(&tempdetail); + if (!detail) + hlist_del(&tempdetail.datainfo.node); +} - // Replace temp alloc space with final alloc space - pprev = tempdetail.datainfo.node.pprev; - hlist_del(&tempdetail.datainfo.node); - memcpy(&detail->datainfo, &tempdetail.datainfo, sizeof(detail->datainfo)); - detail->handle = MALLOC_DEFAULT_HANDLE; - hlist_add(&detail->datainfo.node, pprev); +// Release space allocated with alloc_new() +static void +alloc_free(struct allocinfo_s *info) +{ + struct allocinfo_s *next = container_of_or_null( + info->node.next, struct allocinfo_s, node); + if (next && next->range_end == info->range_start) + next->range_end = info->range_end; + hlist_del(&info->node); } -// Search all zones for an allocation obtained from allocSpace() +// Search all zones for an allocation obtained from alloc_new() static struct allocinfo_s * -findAlloc(void *data) +alloc_find(u32 data) { int i; for (i=0; i<ARRAY_SIZE(Zones); i++) { struct allocinfo_s *info; hlist_for_each_entry(info, &Zones[i]->head, node) { - if (info->data == data) + if (info->range_start == data) return info; } } return NULL; } -// Return the last sentinal node of a zone +// Find the lowest memory range added by alloc_add() static struct allocinfo_s * -findLast(struct zone_s *zone) +alloc_find_lowest(struct zone_s *zone) { struct allocinfo_s *info, *last = NULL; hlist_for_each_entry(info, &zone->head, node) { @@ -171,25 +180,25 @@ relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size) } // Support expanding the ZoneLow dynamically. -static void * +static u32 zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill) { // Make sure to not move ebda while an optionrom is running. if (unlikely(wait_preempt())) { - void *data = allocSpace(&ZoneLow, size, align, fill); + u32 data = alloc_new(&ZoneLow, size, align, fill); if (data) return data; } - struct allocinfo_s *info = findLast(&ZoneLow); + struct allocinfo_s *info = alloc_find_lowest(&ZoneLow); if (!info) - return NULL; - u32 oldpos = (u32)info->allocend; + return 0; + u32 oldpos = info->range_end; u32 newpos = ALIGN_DOWN(oldpos - size, align); - u32 bottom = (u32)info->dataend; + u32 bottom = info->range_start + info->alloc_size; if (newpos >= bottom && newpos <= oldpos) // Space already present. - return allocSpace(&ZoneLow, size, align, fill); + return alloc_new(&ZoneLow, size, align, fill); u16 ebda_seg = get_ebda_seg(); u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0); u8 ebda_size = GET_EBDA(ebda_seg, size); @@ -201,21 +210,20 @@ zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill) u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024); if (newebda < BUILD_EBDA_MINIMUM) // Not enough space. - return NULL; + return 0; // Move ebda int ret = relocate_ebda(newebda, ebda_pos, ebda_size); if (ret) - return NULL; + return 0; // Update zone - if (ebda_end == bottom) { - info->data = (void*)newbottom; - info->dataend = (void*)newbottom; - } else - addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end); + if (ebda_end == bottom) + info->range_start = newbottom; + else + alloc_add(&ZoneLow, newbottom, ebda_end); - return allocSpace(&ZoneLow, size, align, fill); + return alloc_new(&ZoneLow, size, align, fill); } @@ -223,56 +231,69 @@ zonelow_expand(u32 size, u32 align, struct allocinfo_s *fill) * tracked memory allocations ****************************************************************/ -// Allocate memory from the given zone and track it as a PMM allocation -void * __malloc -_malloc(struct zone_s *zone, u32 size, u32 align) +// Allocate physical memory from the given zone and track it as a PMM allocation +u32 +malloc_palloc(struct zone_s *zone, u32 size, u32 align) { ASSERT32FLAT(); if (!size) - return NULL; - - // Find and reserve space for bookkeeping. - struct allocdetail_s *detail = allocSpace( - &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL); - if (!detail) { - detail = allocSpace(&ZoneTmpLow, sizeof(*detail) - , MALLOC_MIN_ALIGN, NULL); - if (!detail) - return NULL; - } - detail->handle = MALLOC_DEFAULT_HANDLE; + return 0; // Find and reserve space for main allocation - void *data = allocSpace(zone, size, align, &detail->datainfo); + struct allocdetail_s tempdetail; + tempdetail.handle = MALLOC_DEFAULT_HANDLE; + u32 data = alloc_new(zone, size, align, &tempdetail.datainfo); if (!CONFIG_MALLOC_UPPERMEMORY && !data && zone == &ZoneLow) - data = zonelow_expand(size, align, &detail->datainfo); - if (!data) { - freeSpace(&detail->detailinfo); - return NULL; + data = zonelow_expand(size, align, &tempdetail.datainfo); + if (!data) + return 0; + + // Find and reserve space for bookkeeping. + struct allocdetail_s *detail = alloc_new_detail(&tempdetail); + if (!detail) { + alloc_free(&tempdetail.datainfo); + return 0; } - dprintf(8, "_malloc zone=%p size=%d align=%x ret=%p (detail=%p)\n" + dprintf(8, "phys_alloc zone=%p size=%d align=%x ret=%x (detail=%p)\n" , zone, size, align, data, detail); return data; } -// Free a data block allocated with _malloc +// Allocate virtual memory from the given zone +void * __malloc +_malloc(struct zone_s *zone, u32 size, u32 align) +{ + return memremap(malloc_palloc(zone, size, align), size); +} + +// Free a data block allocated with phys_alloc int -_free(void *data) +malloc_pfree(u32 data) { ASSERT32FLAT(); - struct allocinfo_s *info = findAlloc(data); - if (!info || data == (void*)info || data == info->dataend) + struct allocinfo_s *info = alloc_find(data); + if (!info || data == virt_to_phys(info) || !info->alloc_size) return -1; struct allocdetail_s *detail = container_of( info, struct allocdetail_s, datainfo); - dprintf(8, "_free %p (detail=%p)\n", data, detail); - freeSpace(info); - freeSpace(&detail->detailinfo); + dprintf(8, "phys_free %x (detail=%p)\n", data, detail); + alloc_free(info); + alloc_free(&detail->detailinfo); return 0; } +void +free(void *data) +{ + if (!data) + return; + int ret = malloc_pfree(virt_to_phys(data)); + if (ret) + warn_internalerror(); +} + // Find the amount of free space in a given zone. u32 malloc_getspace(struct zone_s *zone) @@ -282,7 +303,7 @@ malloc_getspace(struct zone_s *zone) u32 maxspace = 0; struct allocinfo_s *info; hlist_for_each_entry(info, &zone->head, node) { - u32 space = info->allocend - info->dataend; + u32 space = info->range_end - info->range_start - info->alloc_size; if (space > maxspace) maxspace = space; } @@ -298,34 +319,34 @@ malloc_getspace(struct zone_s *zone) // Set a handle associated with an allocation. void -malloc_sethandle(void *data, u32 handle) +malloc_sethandle(u32 data, u32 handle) { ASSERT32FLAT(); - struct allocinfo_s *info = findAlloc(data); - if (!info || data == (void*)info || data == info->dataend) + struct allocinfo_s *info = alloc_find(data); + if (!info || data == virt_to_phys(info) || !info->alloc_size) return; struct allocdetail_s *detail = container_of( info, struct allocdetail_s, datainfo); detail->handle = handle; } -// Find the data block allocated with _malloc with a given handle. -void * +// Find the data block allocated with phys_alloc with a given handle. +u32 malloc_findhandle(u32 handle) { int i; for (i=0; i<ARRAY_SIZE(Zones); i++) { struct allocinfo_s *info; hlist_for_each_entry(info, &Zones[i]->head, node) { - if (info->data != (void*)info) + if (info->range_start != virt_to_phys(info)) continue; struct allocdetail_s *detail = container_of( info, struct allocdetail_s, detailinfo); if (detail->handle == handle) - return detail->datainfo.data; + return detail->datainfo.range_start; } } - return NULL; + return 0; } @@ -343,10 +364,9 @@ u32 rom_get_max(void) { if (CONFIG_MALLOC_UPPERMEMORY) - return ALIGN_DOWN((u32)RomBase->allocend - OPROM_HEADER_RESERVE + return ALIGN_DOWN(RomBase->range_end - OPROM_HEADER_RESERVE , OPTION_ROM_ALIGN); - extern u8 final_readonly_start[]; - return (u32)final_readonly_start; + return SYMBOL(final_readonly_start); } // Return the end of the last deployed option rom. @@ -364,9 +384,9 @@ rom_reserve(u32 size) if (newend > rom_get_max()) return NULL; if (CONFIG_MALLOC_UPPERMEMORY) { - if (newend < (u32)zonelow_base) - newend = (u32)zonelow_base; - RomBase->data = RomBase->dataend = (void*)newend + OPROM_HEADER_RESERVE; + if (newend < SYMBOL(zonelow_base)) + newend = SYMBOL(zonelow_base); + RomBase->range_start = newend + OPROM_HEADER_RESERVE; } return (void*)RomEnd; } @@ -396,10 +416,10 @@ malloc_preinit(void) dprintf(3, "malloc preinit\n"); // Don't declare any memory between 0xa0000 and 0x100000 - add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE); + e820_remove(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END); // Mark known areas as reserved. - add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED); + e820_add(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED); // Populate temp high ram u32 highram = 0; @@ -419,31 +439,30 @@ malloc_preinit(void) e = newe; } } - addSpace(&ZoneTmpHigh, (void*)s, (void*)e); + alloc_add(&ZoneTmpHigh, s, e); } // Populate regions - addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM); + alloc_add(&ZoneTmpLow, BUILD_STACK_ADDR, BUILD_EBDA_MINIMUM); if (highram) { - addSpace(&ZoneHigh, (void*)highram - , (void*)highram + BUILD_MAX_HIGHTABLE); - add_e820(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED); + alloc_add(&ZoneHigh, highram, highram + BUILD_MAX_HIGHTABLE); + e820_add(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED); } } void -csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size) +malloc_csm_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size) { ASSERT32FLAT(); if (hi_pmm_size > BUILD_MAX_HIGHTABLE) { - void *hi_pmm_end = (void *)hi_pmm + hi_pmm_size; - addSpace(&ZoneTmpHigh, (void *)hi_pmm, hi_pmm_end - BUILD_MAX_HIGHTABLE); - addSpace(&ZoneHigh, hi_pmm_end - BUILD_MAX_HIGHTABLE, hi_pmm_end); + u32 hi_pmm_end = hi_pmm + hi_pmm_size; + alloc_add(&ZoneTmpHigh, hi_pmm, hi_pmm_end - BUILD_MAX_HIGHTABLE); + alloc_add(&ZoneHigh, hi_pmm_end - BUILD_MAX_HIGHTABLE, hi_pmm_end); } else { - addSpace(&ZoneTmpHigh, (void *)hi_pmm, (void *)hi_pmm + hi_pmm_size); + alloc_add(&ZoneTmpHigh, hi_pmm, hi_pmm + hi_pmm_size); } - addSpace(&ZoneTmpLow, (void *)low_pmm, (void *)low_pmm + low_pmm_size); + alloc_add(&ZoneTmpLow, low_pmm, low_pmm + low_pmm_size); } u32 LegacyRamSize VARFSEG; @@ -484,21 +503,21 @@ malloc_init(void) } // Initialize low-memory region - extern u8 varlow_start[], varlow_end[], final_varlow_start[]; - memmove(final_varlow_start, varlow_start, varlow_end - varlow_start); + memmove(VSYMBOL(final_varlow_start), VSYMBOL(varlow_start) + , SYMBOL(varlow_end) - SYMBOL(varlow_start)); if (CONFIG_MALLOC_UPPERMEMORY) { - addSpace(&ZoneLow, zonelow_base + OPROM_HEADER_RESERVE - , final_varlow_start); - RomBase = findLast(&ZoneLow); + alloc_add(&ZoneLow, SYMBOL(zonelow_base) + OPROM_HEADER_RESERVE + , SYMBOL(final_varlow_start)); + RomBase = alloc_find_lowest(&ZoneLow); } else { - addSpace(&ZoneLow, (void*)ALIGN_DOWN((u32)final_varlow_start, 1024) - , final_varlow_start); + alloc_add(&ZoneLow, ALIGN_DOWN(SYMBOL(final_varlow_start), 1024) + , SYMBOL(final_varlow_start)); } // Add space available in f-segment to ZoneFSeg - extern u8 zonefseg_start[], zonefseg_end[]; - memset(zonefseg_start, 0, zonefseg_end - zonefseg_start); - addSpace(&ZoneFSeg, zonefseg_start, zonefseg_end); + memset(VSYMBOL(zonefseg_start), 0 + , SYMBOL(zonefseg_end) - SYMBOL(zonefseg_start)); + alloc_add(&ZoneFSeg, SYMBOL(zonefseg_start), SYMBOL(zonefseg_end)); calcRamSize(); } @@ -521,19 +540,20 @@ malloc_prepboot(void) // Reserve more low-mem if needed. u32 endlow = GET_BDA(mem_size_kb)*1024; - add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED); + e820_add(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED); // Clear unused f-seg ram. - struct allocinfo_s *info = findLast(&ZoneFSeg); - memset(info->dataend, 0, info->allocend - info->dataend); + struct allocinfo_s *info = alloc_find_lowest(&ZoneFSeg); + u32 size = info->range_end - info->range_start; + memset(memremap(info->range_start, size), 0, size); dprintf(1, "Space available for UMB: %x-%x, %x-%x\n" - , RomEnd, base, (u32)info->dataend, (u32)info->allocend); + , RomEnd, base, info->range_start, info->range_end); // Give back unused high ram. - info = findLast(&ZoneHigh); + info = alloc_find_lowest(&ZoneHigh); if (info) { - u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE); - add_e820((u32)info->dataend, giveback, E820_RAM); + u32 giveback = ALIGN_DOWN(info->range_end-info->range_start, PAGE_SIZE); + e820_add(info->range_start, giveback, E820_RAM); dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback); } diff --git a/roms/seabios/src/malloc.h b/roms/seabios/src/malloc.h index 2bcb5bf6d..960a7f800 100644 --- a/roms/seabios/src/malloc.h +++ b/roms/seabios/src/malloc.h @@ -9,17 +9,19 @@ u32 rom_get_max(void); u32 rom_get_last(void); struct rom_header *rom_reserve(u32 size); int rom_confirm(u32 size); -void csm_malloc_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, +void malloc_csm_preinit(u32 low_pmm, u32 low_pmm_size, u32 hi_pmm, u32 hi_pmm_size); void malloc_preinit(void); extern u32 LegacyRamSize; void malloc_init(void); void malloc_prepboot(void); +u32 malloc_palloc(struct zone_s *zone, u32 size, u32 align); void *_malloc(struct zone_s *zone, u32 size, u32 align); -int _free(void *data); +int malloc_pfree(u32 data); +void free(void *data); u32 malloc_getspace(struct zone_s *zone); -void malloc_sethandle(void *data, u32 handle); -void *malloc_findhandle(u32 handle); +void malloc_sethandle(u32 data, u32 handle); +u32 malloc_findhandle(u32 handle); #define MALLOC_DEFAULT_HANDLE 0xFFFFFFFF // Minimum alignment of malloc'd memory @@ -64,8 +66,5 @@ static inline void *memalign_tmp(u32 align, u32 size) { return ret; return memalign_tmplow(align, size); } -static inline void free(void *data) { - _free(data); -} #endif // malloc.h diff --git a/roms/seabios/src/memmap.h b/roms/seabios/src/memmap.h index 7bda56e2b..22bd4bcb8 100644 --- a/roms/seabios/src/memmap.h +++ b/roms/seabios/src/memmap.h @@ -1,29 +1,21 @@ -#ifndef __E820MAP_H -#define __E820MAP_H +#ifndef __MEMMAP_H +#define __MEMMAP_H -#include "types.h" // u64 - -#define E820_RAM 1 -#define E820_RESERVED 2 -#define E820_ACPI 3 -#define E820_NVS 4 -#define E820_UNUSABLE 5 -#define E820_HOLE ((u32)-1) // Useful for removing entries - -struct e820entry { - u64 start; - u64 size; - u32 type; -}; - -void add_e820(u64 start, u64 size, u32 type); -void memmap_prepboot(void); +#include "types.h" // u32 // A typical OS page size #define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 + +static inline u32 virt_to_phys(void *v) { + return (u32)v; +} +static inline void *memremap(u32 addr, u32 len) { + return (void*)addr; +} -// e820 map storage -extern struct e820entry e820_list[]; -extern int e820_count; +// Return the value of a linker script symbol (see scripts/layoutrom.py) +#define SYMBOL(SYM) ({ extern char SYM; (u32)&SYM; }) +#define VSYMBOL(SYM) ((void*)SYMBOL(SYM)) -#endif // e820map.h +#endif // memmap.h diff --git a/roms/seabios/src/misc.c b/roms/seabios/src/misc.c index 8caaf31d8..f02237c36 100644 --- a/roms/seabios/src/misc.c +++ b/roms/seabios/src/misc.c @@ -56,7 +56,7 @@ void VISIBLE16 handle_10(struct bregs *regs) { debug_enter(regs, DEBUG_HDL_10); - // dont do anything, since the VGA BIOS handles int10h requests + // don't do anything, since the VGA BIOS handles int10h requests } // NMI handler diff --git a/roms/seabios/src/mouse.c b/roms/seabios/src/mouse.c index 6d1f5b77e..b7ad7c62a 100644 --- a/roms/seabios/src/mouse.c +++ b/roms/seabios/src/mouse.c @@ -280,8 +280,7 @@ invoke_mouse_handler(void) if (!CONFIG_MOUSE) return; if (need_hop_back()) { - extern void _cfunc16_invoke_mouse_handler(void); - stack_hop_back(0, 0, _cfunc16_invoke_mouse_handler); + stack_hop_back(invoke_mouse_handler, 0, 0); return; } ASSERT16(); diff --git a/roms/seabios/src/optionroms.c b/roms/seabios/src/optionroms.c index 93d9d2fe6..c81eff2d2 100644 --- a/roms/seabios/src/optionroms.c +++ b/roms/seabios/src/optionroms.c @@ -19,6 +19,9 @@ #include "std/pnpbios.h" // PNP_SIGNATURE #include "string.h" // memset #include "util.h" // get_pnp_offset +#include "tcgbios.h" // tpm_* + +static int EnforceChecksum, S3ResumeVga, RunPCIroms; /**************************************************************** @@ -60,8 +63,6 @@ call_bcv(u16 seg, u16 ip) __callrom(MAKE_FLATPTR(seg, 0), ip, 0); } -static int EnforceChecksum; - // Verify that an option rom looks valid static int is_valid_rom(struct rom_header *rom) @@ -132,6 +133,8 @@ init_optionrom(struct rom_header *rom, u16 bdf, int isvga) if (newrom != rom) memmove(newrom, rom, rom->size * 512); + tpm_option_rom(newrom, rom->size * 512); + if (isvga || get_pnp_rom(newrom)) // Only init vga and PnP roms here. callrom(newrom, bdf); @@ -180,19 +183,6 @@ deploy_romfile(struct romfile_s *file) return rom; } -// Check if an option rom is at a hardcoded location or in CBFS. -static struct rom_header * -lookup_hardcode(struct pci_device *pci) -{ - char fname[17]; - snprintf(fname, sizeof(fname), "pci%04x,%04x.rom" - , pci->vendor, pci->device); - struct romfile_s *file = romfile_find(fname); - if (file) - return deploy_romfile(file); - return NULL; -} - // Run all roms in a given CBFS directory. static void run_file_roms(const char *prefix, int isvga, u64 *sources) @@ -321,21 +311,28 @@ fail: } // Attempt to map and initialize the option rom on a given PCI device. -static int +static void init_pcirom(struct pci_device *pci, int isvga, u64 *sources) { u16 bdf = pci->bdf; dprintf(4, "Attempting to init PCI bdf %02x:%02x.%x (vd %04x:%04x)\n" , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf) , pci->vendor, pci->device); - struct rom_header *rom = lookup_hardcode(pci); - if (! rom) + + char fname[17]; + snprintf(fname, sizeof(fname), "pci%04x,%04x.rom" + , pci->vendor, pci->device); + struct romfile_s *file = romfile_find(fname); + struct rom_header *rom = NULL; + if (file) + rom = deploy_romfile(file); + else if (RunPCIroms > 1 || (RunPCIroms == 1 && isvga)) rom = map_pcirom(pci); if (! rom) // No ROM present. - return -1; + return; setRomSource(sources, rom, RS_PCIROM | (u32)pci); - return init_optionrom(rom, bdf, isvga); + init_optionrom(rom, bdf, isvga); } @@ -416,7 +413,6 @@ optionrom_setup(void) * VGA init ****************************************************************/ -static int S3ResumeVga; int ScreenAndDebug; struct rom_header *VgaROM; @@ -432,6 +428,7 @@ vgarom_setup(void) // Load some config settings that impact VGA. EnforceChecksum = romfile_loadint("etc/optionroms-checksum", 1); S3ResumeVga = romfile_loadint("etc/s3-resume-vga-init", CONFIG_QEMU); + RunPCIroms = romfile_loadint("etc/pci-optionrom-exec", 2); ScreenAndDebug = romfile_loadint("etc/screen-and-debug", 1); if (CONFIG_OPTIONROMS_DEPLOYED) { diff --git a/roms/seabios/src/output.c b/roms/seabios/src/output.c index 45397b3f6..8a883889c 100644 --- a/roms/seabios/src/output.c +++ b/roms/seabios/src/output.c @@ -30,6 +30,7 @@ void debug_banner(void) { dprintf(1, "SeaBIOS (version %s)\n", VERSION); + dprintf(1, "BUILD: %s\n", BUILDINFO); } // Write a character to debug port(s). diff --git a/roms/seabios/src/pmm.c b/roms/seabios/src/pmm.c index 304faab2c..640341472 100644 --- a/roms/seabios/src/pmm.c +++ b/roms/seabios/src/pmm.c @@ -65,26 +65,26 @@ handle_pmm00(u16 *args) if (align < MALLOC_MIN_ALIGN) align = MALLOC_MIN_ALIGN; } - void *data; + u32 data; switch (flags & 3) { default: case 0: return 0; case 1: - data = _malloc(lowzone, size, align); + data = malloc_palloc(lowzone, size, align); break; case 2: - data = _malloc(highzone, size, align); + data = malloc_palloc(highzone, size, align); break; case 3: { - data = _malloc(lowzone, size, align); + data = malloc_palloc(lowzone, size, align); if (!data) - data = _malloc(highzone, size, align); + data = malloc_palloc(highzone, size, align); } } if (data && handle != MALLOC_DEFAULT_HANDLE) malloc_sethandle(data, handle); - return (u32)data; + return data; } // PMM - find @@ -95,7 +95,7 @@ handle_pmm01(u16 *args) dprintf(3, "pmm01: handle=%x\n", handle); if (handle == MALLOC_DEFAULT_HANDLE) return 0; - return (u32)malloc_findhandle(handle); + return malloc_findhandle(handle); } // PMM - deallocate @@ -104,7 +104,7 @@ handle_pmm02(u16 *args) { u32 buffer = *(u32*)&args[1]; dprintf(3, "pmm02: buffer=%x\n", buffer); - int ret = _free((void*)buffer); + int ret = malloc_pfree(buffer); if (ret) // Error return 1; diff --git a/roms/seabios/src/post.c b/roms/seabios/src/post.c index 9ea5620c9..49c22b875 100644 --- a/roms/seabios/src/post.c +++ b/roms/seabios/src/post.c @@ -8,6 +8,7 @@ #include "biosvar.h" // SET_BDA #include "bregs.h" // struct bregs #include "config.h" // CONFIG_* +#include "e820map.h" // e820_add #include "fw/paravirt.h" // qemu_cfg_preinit #include "fw/xen.h" // xen_preinit #include "hw/ahci.h" // ahci_setup @@ -24,10 +25,11 @@ #include "hw/virtio-blk.h" // virtio_blk_setup #include "hw/virtio-scsi.h" // virtio_scsi_setup #include "malloc.h" // malloc_init -#include "memmap.h" // add_e820 +#include "memmap.h" // SYMBOL #include "output.h" // dprintf #include "string.h" // memset #include "util.h" // kbd_init +#include "tcgbios.h" // tpm_* /**************************************************************** @@ -88,9 +90,8 @@ bda_init(void) int esize = EBDA_SIZE_START; u16 ebda_seg = EBDA_SEGMENT_START; - extern u8 final_varlow_start[]; if (!CONFIG_MALLOC_UPPERMEMORY) - ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN((u32)final_varlow_start, 1024) + ebda_seg = FLATPTR_TO_SEG(ALIGN_DOWN(SYMBOL(final_varlow_start), 1024) - EBDA_SIZE_START*1024); SET_BDA(ebda_seg, ebda_seg); @@ -101,10 +102,10 @@ bda_init(void) memset(ebda, 0, sizeof(*ebda)); ebda->size = esize; - add_e820((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED); + e820_add((u32)ebda, BUILD_LOWRAM_END-(u32)ebda, E820_RESERVED); // Init extra stack - StackPos = (void*)(&ExtraStack[BUILD_EXTRA_STACK_SIZE] - zonelow_base); + StackPos = &ExtraStack[BUILD_EXTRA_STACK_SIZE] - SYMBOL(zonelow_base); } void @@ -116,13 +117,13 @@ interface_init(void) // Setup romfile items. qemu_cfg_init(); coreboot_cbfs_init(); + multiboot_init(); // Setup ivt/bda/ebda ivt_init(); bda_init(); // Other interfaces - thread_init(); boot_init(); bios32_init(); pmm_init(); @@ -157,26 +158,32 @@ device_hardware_setup(void) static void platform_hardware_setup(void) { - // Enable CPU caching - setcr0(getcr0() & ~(CR0_CD|CR0_NW)); - // Make sure legacy DMA isn't running. dma_setup(); // Init base pc hardware. pic_setup(); + thread_setup(); mathcp_setup(); - timer_setup(); - clock_setup(); // Platform specific setup qemu_platform_setup(); coreboot_platform_setup(); + + // Setup timers and periodic clock interrupt + timer_setup(); + clock_setup(); + + // Initialize TPM + tpm_setup(); } void prepareboot(void) { + // Change TPM phys. presence state befor leaving BIOS + tpm_prepboot(); + // Run BCVs bcv_prepboot(); @@ -184,7 +191,7 @@ prepareboot(void) cdrom_prepboot(); pmm_prepboot(); malloc_prepboot(); - memmap_prepboot(); + e820_prepboot(); HaveRunPost = 2; @@ -269,30 +276,27 @@ reloc_preinit(void *f, void *arg) void (*func)(void *) __noreturn = f; if (!CONFIG_RELOCATE_INIT) func(arg); - // Symbols populated by the build. - extern u8 code32flat_start[]; - extern u8 _reloc_min_align; - extern u32 _reloc_abs_start[], _reloc_abs_end[]; - extern u32 _reloc_rel_start[], _reloc_rel_end[]; - extern u32 _reloc_init_start[], _reloc_init_end[]; - extern u8 code32init_start[], code32init_end[]; // Allocate space for init code. - u32 initsize = code32init_end - code32init_start; - u32 codealign = (u32)&_reloc_min_align; + u32 initsize = SYMBOL(code32init_end) - SYMBOL(code32init_start); + u32 codealign = SYMBOL(_reloc_min_align); void *codedest = memalign_tmp(codealign, initsize); + void *codesrc = VSYMBOL(code32init_start); if (!codedest) panic("No space for init relocation.\n"); // Copy code and update relocs (init absolute, init relative, and runtime) dprintf(1, "Relocating init from %p to %p (size %d)\n" - , code32init_start, codedest, initsize); - s32 delta = codedest - (void*)code32init_start; - memcpy(codedest, code32init_start, initsize); - updateRelocs(codedest, _reloc_abs_start, _reloc_abs_end, delta); - updateRelocs(codedest, _reloc_rel_start, _reloc_rel_end, -delta); - updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta); - if (f >= (void*)code32init_start && f < (void*)code32init_end) + , codesrc, codedest, initsize); + s32 delta = codedest - codesrc; + memcpy(codedest, codesrc, initsize); + updateRelocs(codedest, VSYMBOL(_reloc_abs_start), VSYMBOL(_reloc_abs_end) + , delta); + updateRelocs(codedest, VSYMBOL(_reloc_rel_start), VSYMBOL(_reloc_rel_end) + , -delta); + updateRelocs(VSYMBOL(code32flat_start), VSYMBOL(_reloc_init_start) + , VSYMBOL(_reloc_init_end), delta); + if (f >= codesrc && f < VSYMBOL(code32init_end)) func = f + delta; // Call function in relocated code. diff --git a/roms/seabios/src/resume.c b/roms/seabios/src/resume.c index 19031747c..a5465d877 100644 --- a/roms/seabios/src/resume.c +++ b/roms/seabios/src/resume.c @@ -16,6 +16,7 @@ #include "std/bda.h" // struct bios_data_area_s #include "string.h" // memset #include "util.h" // dma_setup +#include "tcgbios.h" // tpm_s3_resume // Handler for post calls that look like a resume. void VISIBLE16 @@ -99,6 +100,8 @@ s3_resume(void) pci_resume(); + /* resume TPM before we may measure option roms */ + tpm_s3_resume(); s3_resume_vga(); make_bios_readonly(); diff --git a/roms/seabios/src/romlayout.S b/roms/seabios/src/romlayout.S index 93b6874e7..53cc0f5e3 100644 --- a/roms/seabios/src/romlayout.S +++ b/roms/seabios/src/romlayout.S @@ -22,18 +22,14 @@ // %edx = return location (in 32bit mode) // Clobbers: ecx, flags, segment registers, cr0, idt/gdt DECLFUNC transition32 -transition32_nmi_off: - // transition32 when NMI and A20 are already initialized - movl %eax, %ecx - jmp 1f + .global transition32_nmi_off transition32: - movl %eax, %ecx - // Disable irqs (and clear direction flag) cli cld // Disable nmi + movl %eax, %ecx movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax outb %al, $PORT_CMOS_INDEX inb $PORT_CMOS_DATA, %al @@ -42,29 +38,31 @@ transition32: inb $PORT_A20, %al orb $A20_ENABLE_BIT, %al outb %al, $PORT_A20 + movl %ecx, %eax +transition32_nmi_off: // Set segment descriptors -1: lidtw %cs:pmode_IDT_info + lidtw %cs:pmode_IDT_info lgdtw %cs:rombios32_gdt_48 // Enable protected mode - movl %cr0, %eax - orl $CR0_PE, %eax - movl %eax, %cr0 + movl %cr0, %ecx + andl $~(CR0_PG|CR0_CD|CR0_NW), %ecx + orl $CR0_PE, %ecx + movl %ecx, %cr0 // start 32bit protected mode code - ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 2f) + ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f) .code32 // init data segments -2: movl $SEG32_MODE32_DS, %eax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw %ax, %fs - movw %ax, %gs +1: movl $SEG32_MODE32_DS, %ecx + movw %cx, %ds + movw %cx, %es + movw %cx, %ss + movw %cx, %fs + movw %cx, %gs - movl %ecx, %eax jmpl *%edx .code16 @@ -75,61 +73,47 @@ transition32: .global transition16big .code32 transition16: - movl %eax, %ecx - - // restore data segment limits to 0xffff - movl $SEG32_MODE16_DS, %eax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw %ax, %fs - movw %ax, %gs - -#if CONFIG_DISABLE_A20 - // disable a20 - inb $PORT_A20, %al - andb $~A20_ENABLE_BIT, %al - outb %al, $PORT_A20 -#endif + // Reset data segment limits + movl $SEG32_MODE16_DS, %ecx + movw %cx, %ds + movw %cx, %es + movw %cx, %ss + movw %cx, %fs + movw %cx, %gs // Jump to 16bit mode ljmpw $SEG32_MODE16_CS, $1f transition16big: - movl %eax, %ecx - - movl $SEG32_MODE16BIG_DS, %eax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw %ax, %fs - movw %ax, %gs + movl $SEG32_MODE16BIG_DS, %ecx + movw %cx, %ds + movw %cx, %es + movw %cx, %ss + movw %cx, %fs + movw %cx, %gs ljmpw $SEG32_MODE16BIG_CS, $1f .code16 -1: // Disable protected mode - movl %cr0, %eax - andl $~CR0_PE, %eax - movl %eax, %cr0 +1: movl %cr0, %ecx + andl $~CR0_PE, %ecx + movl %ecx, %cr0 // far jump to flush CPU queue after transition to real mode ljmpw $SEG_BIOS, $2f -2: // restore IDT to normal real-mode defaults - lidtw %cs:rmode_IDT_info +2: lidtw %cs:rmode_IDT_info // Clear segment registers - xorw %ax, %ax - movw %ax, %fs - movw %ax, %gs - movw %ax, %es - movw %ax, %ds - movw %ax, %ss // Assume stack is in segment 0 + xorw %cx, %cx + movw %cx, %fs + movw %cx, %gs + movw %cx, %es + movw %cx, %ds + movw %cx, %ss // Assume stack is in segment 0 - movl %ecx, %eax jmpl *%edx @@ -264,7 +248,7 @@ entry_pmm: movl $_cfunc32flat_handle_pmm, %eax // Setup: call32(handle_pmm, args, -1) leal PUSHBREGS_size+12(%esp, %ecx), %edx // %edx points to start of args movl $-1, %ecx - calll call32 + calll __call32 movw %ax, BREGS_eax(%esp) // Modify %ax:%dx to return %eax shrl $16, %eax movw %ax, BREGS_edx(%esp) @@ -374,6 +358,8 @@ entry_bios32: entry_elf: cli cld + movl %eax, entry_elf_eax + movl %ebx, entry_elf_ebx lidtl (BUILD_BIOS_ADDR + pmode_IDT_info) lgdtl (BUILD_BIOS_ADDR + rombios32_gdt_48) movl $SEG32_MODE32_DS, %eax @@ -562,7 +548,10 @@ entry_post: ENTRY_INTO32 _cfunc32flat_handle_post // Normal entry point ORG 0xe2c3 - IRQ_ENTRY 02 + .global entry_02 +entry_02: + ENTRY handle_02 // NMI handler does not switch onto extra stack + iretw ORG 0xe3fe .global entry_13_official diff --git a/roms/seabios/src/sha1.c b/roms/seabios/src/sha1.c new file mode 100644 index 000000000..2ecb3cb89 --- /dev/null +++ b/roms/seabios/src/sha1.c @@ -0,0 +1,147 @@ +// Support for Calculation of SHA1 in SW +// +// Copyright (C) 2006-2011 IBM Corporation +// +// Authors: +// Stefan Berger <stefanb@linux.vnet.ibm.com> +// +// This file may be distributed under the terms of the GNU LGPLv3 license. +// +// See: http://www.itl.nist.gov/fipspubs/fip180-1.htm +// RFC3174, Wikipedia's SHA1 alogrithm description +// + +#include "config.h" +#include "byteorder.h" // cpu_to_*, __swab64 +#include "sha1.h" // sha1 +#include "string.h" // memcpy +#include "x86.h" // rol + +typedef struct _sha1_ctx { + u32 h[5]; +} sha1_ctx; + + +static void +sha1_block(u32 *w, sha1_ctx *ctx) +{ + u32 i; + u32 a,b,c,d,e,f; + u32 tmp; + u32 idx; + + static const u32 sha_ko[4] = { + 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; + + /* change endianness of given data */ + for (i = 0; i < 16; i++) + w[i] = be32_to_cpu(w[i]); + + for (i = 16; i <= 79; i++) { + tmp = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]; + w[i] = rol(tmp,1); + } + + a = ctx->h[0]; + b = ctx->h[1]; + c = ctx->h[2]; + d = ctx->h[3]; + e = ctx->h[4]; + + for (i = 0; i <= 79; i++) { + if (i <= 19) { + f = (b & c) | ((b ^ 0xffffffff) & d); + idx = 0; + } else if (i <= 39) { + f = b ^ c ^ d; + idx = 1; + } else if (i <= 59) { + f = (b & c) | (b & d) | (c & d); + idx = 2; + } else { + f = b ^ c ^ d; + idx = 3; + } + + tmp = rol(a, 5) + + f + + e + + sha_ko[idx] + + w[i]; + e = d; + d = c; + c = rol(b, 30); + b = a; + a = tmp; + } + + ctx->h[0] += a; + ctx->h[1] += b; + ctx->h[2] += c; + ctx->h[3] += d; + ctx->h[4] += e; +} + + +static void +sha1_do(sha1_ctx *ctx, const u8 *data32, u32 length) +{ + u32 offset; + u16 num; + u32 bits = 0; + u32 w[80]; + u64 tmp; + + /* treat data in 64-byte chunks */ + for (offset = 0; length - offset >= 64; offset += 64) { + memcpy(w, data32 + offset, 64); + sha1_block((u32 *)w, ctx); + bits += (64 * 8); + } + + /* last block with less than 64 bytes */ + num = length - offset; + bits += (num << 3); + + memcpy(w, data32 + offset, num); + ((u8 *)w)[num] = 0x80; + if (64 - (num + 1) > 0) + memset( &((u8 *)w)[num + 1], 0x0, 64 - (num + 1)); + + if (num >= 56) { + /* cannot append number of bits here */ + sha1_block((u32 *)w, ctx); + memset(w, 0x0, 60); + } + + /* write number of bits to end of block */ + tmp = __swab64(bits); + memcpy(&w[14], &tmp, 8); + + sha1_block(w, ctx); + + /* need to switch result's endianness */ + for (num = 0; num < 5; num++) + ctx->h[num] = cpu_to_be32(ctx->h[num]); +} + + +u32 +sha1(const u8 *data, u32 length, u8 *hash) +{ + if (!CONFIG_TCGBIOS) + return 0; + + sha1_ctx ctx = { + .h[0] = 0x67452301, + .h[1] = 0xefcdab89, + .h[2] = 0x98badcfe, + .h[3] = 0x10325476, + .h[4] = 0xc3d2e1f0, + }; + + sha1_do(&ctx, data, length); + memcpy(hash, &ctx.h[0], 20); + + return 0; +} diff --git a/roms/seabios/src/sha1.h b/roms/seabios/src/sha1.h new file mode 100644 index 000000000..07aabf34f --- /dev/null +++ b/roms/seabios/src/sha1.h @@ -0,0 +1,8 @@ +#ifndef __SHA1_H +#define __SHA1_H + +#include "types.h" // u32 + +u32 sha1(const u8 *data, u32 length, u8 *hash); + +#endif // sha1.h diff --git a/roms/seabios/src/stacks.c b/roms/seabios/src/stacks.c index 1dbdfe9bb..ef6a70775 100644 --- a/roms/seabios/src/stacks.c +++ b/roms/seabios/src/stacks.c @@ -1,6 +1,6 @@ // Code for manipulating stack locations. // -// Copyright (C) 2009-2014 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2009-2015 Kevin O'Connor <kevin@koconnor.net> // // This file may be distributed under the terms of the GNU LGPLv3 license. @@ -13,6 +13,7 @@ #include "output.h" // dprintf #include "romfile.h" // romfile_loadint #include "stacks.h" // struct mutex_s +#include "string.h" // memset #include "util.h" // useRTC #define MAIN_STACK_MAX (1024*1024) @@ -27,40 +28,108 @@ struct { u8 cmosindex; u8 a20; u16 ss, fs, gs; + u32 cr0; struct descloc_s gdt; -} Call32Data VARLOW; +} Call16Data VARLOW; -#define C32_SLOPPY 1 -#define C32_SMM 2 +#define C16_BIG 1 +#define C16_SMM 2 int HaveSmmCall32 VARFSEG; -// Backup state in preparation for call32_smm() -static void -call32_smm_prep(void) -{ +// Backup state in preparation for call32 +static int +call32_prep(u8 method) +{ + if (!CONFIG_CALL32_SMM || method != C16_SMM) { + // Backup cr0 + u32 cr0 = cr0_read(); + if (cr0 & CR0_PE) + // Called in 16bit protected mode?! + return -1; + SET_LOW(Call16Data.cr0, cr0); + + // Backup fs/gs and gdt + SET_LOW(Call16Data.fs, GET_SEG(FS)); + SET_LOW(Call16Data.gs, GET_SEG(GS)); + struct descloc_s gdt; + sgdt(&gdt); + SET_LOW(Call16Data.gdt.length, gdt.length); + SET_LOW(Call16Data.gdt.addr, gdt.addr); + + // Enable a20 and backup its previous state + SET_LOW(Call16Data.a20, set_a20(1)); + } + + // Backup ss + SET_LOW(Call16Data.ss, GET_SEG(SS)); + // Backup cmos index register and disable nmi u8 cmosindex = inb(PORT_CMOS_INDEX); outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX); inb(PORT_CMOS_DATA); - SET_LOW(Call32Data.cmosindex, cmosindex); - - // Backup ss - SET_LOW(Call32Data.ss, GET_SEG(SS)); + SET_LOW(Call16Data.cmosindex, cmosindex); - SET_LOW(Call32Data.method, C32_SMM); + SET_LOW(Call16Data.method, method); + return 0; } -// Restore state backed up during call32_smm() -static void -call32_smm_post(void) +// Restore state backed up during call32 +static u8 +call32_post(void) { - SET_LOW(Call32Data.method, 0); - SET_LOW(Call32Data.ss, 0); + u8 method = GET_LOW(Call16Data.method); + SET_LOW(Call16Data.method, 0); + SET_LOW(Call16Data.ss, 0); + + if (!CONFIG_CALL32_SMM || method != C16_SMM) { + // Restore a20 + set_a20(GET_LOW(Call16Data.a20)); + + // Restore gdt and fs/gs + struct descloc_s gdt; + gdt.length = GET_LOW(Call16Data.gdt.length); + gdt.addr = GET_LOW(Call16Data.gdt.addr); + lgdt(&gdt); + SET_SEG(FS, GET_LOW(Call16Data.fs)); + SET_SEG(GS, GET_LOW(Call16Data.gs)); + + // Restore cr0 + u32 cr0_caching = GET_LOW(Call16Data.cr0) & (CR0_CD|CR0_NW); + if (cr0_caching) + cr0_mask(CR0_CD|CR0_NW, cr0_caching); + } // Restore cmos index register - outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX); + outb(GET_LOW(Call16Data.cmosindex), PORT_CMOS_INDEX); inb(PORT_CMOS_DATA); + return method; +} + +// Force next call16() to restore to a pristine cpu environment state +static void +call16_override(int big) +{ + ASSERT32FLAT(); + if (getesp() > BUILD_STACK_ADDR) + panic("call16_override with invalid stack\n"); + memset(&Call16Data, 0, sizeof(Call16Data)); + if (big) { + Call16Data.method = C16_BIG; + Call16Data.a20 = 1; + } else { + Call16Data.a20 = !CONFIG_DISABLE_A20; + } +} + +// 16bit handler code called from call16() / call16_smm() +u32 VISIBLE16 +call16_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx)) +{ + u8 method = call32_post(); + u32 ret = func(eax, edx); + call32_prep(method); + return ret; } #define ASM32_SWITCH16 " .pushsection .text.32fseg." UNIQSEC "\n .code16\n" @@ -74,7 +143,7 @@ call32_smm(void *func, u32 eax) { ASSERT16(); dprintf(9, "call32_smm %p %x\n", func, eax); - call32_smm_prep(); + call32_prep(C16_SMM); u32 bkup_esp; asm volatile( // Backup esp / set esp to flat stack location @@ -109,24 +178,12 @@ call32_smm(void *func, u32 eax) : "=&r" (bkup_esp), "+r" (eax) : "r" (func) : "eax", "ecx", "edx", "ebx", "cc", "memory"); - call32_smm_post(); + call32_post(); dprintf(9, "call32_smm done %p %x\n", func, eax); return eax; } -// 16bit handler code called from call16_smm() -u32 VISIBLE16 -call16_smm_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx)) -{ - if (!CONFIG_CALL32_SMM) - return eax; - call32_smm_post(); - u32 ret = func(eax, edx); - call32_smm_prep(); - return ret; -} - static u32 call16_smm(u32 eax, u32 edx, void *func) { @@ -135,7 +192,7 @@ call16_smm(u32 eax, u32 edx, void *func) return eax; func -= BUILD_BIOS_ADDR; dprintf(9, "call16_smm %p %x %x\n", func, eax, edx); - u32 stackoffset = Call32Data.ss << 4; + u32 stackoffset = Call16Data.ss << 4; asm volatile( // Restore esp " subl %0, %%esp\n" @@ -151,7 +208,7 @@ call16_smm(u32 eax, u32 edx, void *func) ASM32_SWITCH16 "1:movl %1, %%eax\n" " movl %3, %%ecx\n" - " calll _cfunc16_call16_smm_helper\n" + " calll _cfunc16_call16_helper\n" " movl %%eax, %1\n" " movl $" __stringify(CALL32SMM_CMDID) ", %%eax\n" @@ -170,61 +227,18 @@ call16_smm(u32 eax, u32 edx, void *func) return eax; } -// Backup state in preparation for call32_sloppy() -static void -call32_sloppy_prep(void) -{ - // Backup cmos index register and disable nmi - u8 cmosindex = inb(PORT_CMOS_INDEX); - outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX); - inb(PORT_CMOS_DATA); - SET_LOW(Call32Data.cmosindex, cmosindex); - - // Enable a20 and backup it's previous state - SET_LOW(Call32Data.a20, set_a20(1)); - - // Backup ss/fs/gs and gdt - SET_LOW(Call32Data.ss, GET_SEG(SS)); - SET_LOW(Call32Data.fs, GET_SEG(FS)); - SET_LOW(Call32Data.gs, GET_SEG(GS)); - struct descloc_s gdt; - sgdt(&gdt); - SET_LOW(Call32Data.gdt.length, gdt.length); - SET_LOW(Call32Data.gdt.addr, gdt.addr); - - SET_LOW(Call32Data.method, C32_SLOPPY); -} - -// Restore state backed up during call32_sloppy() -static void -call32_sloppy_post(void) -{ - SET_LOW(Call32Data.method, 0); - SET_LOW(Call32Data.ss, 0); - - // Restore gdt and fs/gs - struct descloc_s gdt; - gdt.length = GET_LOW(Call32Data.gdt.length); - gdt.addr = GET_LOW(Call32Data.gdt.addr); - lgdt(&gdt); - SET_SEG(FS, GET_LOW(Call32Data.fs)); - SET_SEG(GS, GET_LOW(Call32Data.gs)); - - // Restore a20 - set_a20(GET_LOW(Call32Data.a20)); - - // Restore cmos index register - outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX); - inb(PORT_CMOS_DATA); -} - -// Call a C function in 32bit mode. This clobbers the 16bit segment -// selector registers. -static u32 -call32_sloppy(void *func, u32 eax) +// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function. +u32 VISIBLE16 +__call32(void *func, u32 eax, u32 errret) { ASSERT16(); - call32_sloppy_prep(); + if (CONFIG_CALL32_SMM && GET_GLOBAL(HaveSmmCall32)) + return call32_smm(func, eax); + // Jump direclty to 32bit mode - this clobbers the 16bit segment + // selector registers. + int ret = call32_prep(C16_BIG); + if (ret) + return errret; u32 bkup_ss, bkup_esp; asm volatile( // Backup ss/esp / set esp to flat stack location @@ -236,7 +250,7 @@ call32_sloppy(void *func, u32 eax) // Transition to 32bit mode, call func, return to 16bit " movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n" - " jmp transition32\n" + " jmp transition32_nmi_off\n" ASM16_SWITCH32 "1:calll *%3\n" " movl $2f, %%edx\n" @@ -250,136 +264,52 @@ call32_sloppy(void *func, u32 eax) : "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax) : "r" (func) : "ecx", "edx", "cc", "memory"); - call32_sloppy_post(); + call32_post(); return eax; } -// 16bit handler code called from call16_sloppy() -u32 VISIBLE16 -call16_sloppy_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx)) -{ - call32_sloppy_post(); - u32 ret = func(eax, edx); - call32_sloppy_prep(); - return ret; -} - -// Jump back to 16bit mode while in 32bit mode from call32_sloppy() +// Call a 16bit SeaBIOS function, restoring the mode from last call32(). static u32 -call16_sloppy(u32 eax, u32 edx, void *func) +call16(u32 eax, u32 edx, void *func) { ASSERT32FLAT(); if (getesp() > MAIN_STACK_MAX) - panic("call16_sloppy with invalid stack\n"); + panic("call16 with invalid stack\n"); + if (CONFIG_CALL32_SMM && Call16Data.method == C16_SMM) + return call16_smm(eax, edx, func); + + extern void transition16big(void); + extern void transition16(void); + void *thunk = transition16; + if (Call16Data.method == C16_BIG || in_post()) + thunk = transition16big; func -= BUILD_BIOS_ADDR; - u32 stackseg = Call32Data.ss; + u32 stackseg = Call16Data.ss; asm volatile( // Transition to 16bit mode " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n" - " jmp transition16big\n" + " jmp *%%ecx\n" // Setup ss/esp and call func ASM32_SWITCH16 - "1:movl %3, %%ecx\n" - " shll $4, %3\n" + "1:movl %2, %%ecx\n" + " shll $4, %2\n" " movw %%cx, %%ss\n" - " subl %3, %%esp\n" + " subl %2, %%esp\n" " movw %%cx, %%ds\n" - " movl %2, %%edx\n" - " movl %1, %%ecx\n" - " calll _cfunc16_call16_sloppy_helper\n" + " movl %4, %%edx\n" + " movl %3, %%ecx\n" + " calll _cfunc16_call16_helper\n" // Return to 32bit and restore esp " movl $2f, %%edx\n" - " jmp transition32\n" - ASM32_BACK32 - "2:addl %3, %%esp\n" - : "+a" (eax) - : "r" (func), "r" (edx), "r" (stackseg) - : "edx", "ecx", "cc", "memory"); - return eax; -} - -// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function. -u32 VISIBLE16 -call32(void *func, u32 eax, u32 errret) -{ - ASSERT16(); - if (CONFIG_CALL32_SMM && GET_GLOBAL(HaveSmmCall32)) - return call32_smm(func, eax); - u32 cr0 = getcr0(); - if (cr0 & CR0_PE) - // Called in 16bit protected mode?! - return errret; - return call32_sloppy(func, eax); -} - -// Call a 16bit SeaBIOS function from a 32bit SeaBIOS function. -static u32 -call16(u32 eax, u32 edx, void *func) -{ - ASSERT32FLAT(); - if (getesp() > BUILD_STACK_ADDR) - panic("call16 with invalid stack\n"); - func -= BUILD_BIOS_ADDR; - asm volatile( - // Transition to 16bit mode - " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n" - " jmp transition16\n" - // Call func - ASM32_SWITCH16 - "1:movl %2, %%edx\n" - " calll *%1\n" - // Return to 32bit - " movl $2f, %%edx\n" - " jmp transition32\n" - ASM32_BACK32 - "2:\n" - : "+a" (eax) - : "r" (func), "r" (edx) - : "edx", "ecx", "cc", "memory"); - return eax; -} - -// Call a 16bit SeaBIOS function in "big real" mode. -static u32 -call16big(u32 eax, u32 edx, void *func) -{ - ASSERT32FLAT(); - if (getesp() > BUILD_STACK_ADDR) - panic("call16big with invalid stack\n"); - func -= BUILD_BIOS_ADDR; - asm volatile( - // Transition to 16bit mode - " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n" - " jmp transition16big\n" - // Call func - ASM32_SWITCH16 - "1:movl %2, %%edx\n" - " calll *%1\n" - // Return to 32bit - " movl $2f, %%edx\n" - " jmp transition32\n" + " jmp transition32_nmi_off\n" ASM32_BACK32 - "2:\n" - : "+a" (eax) + "2:addl %2, %%esp\n" + : "+a" (eax), "+c"(thunk), "+r"(stackseg) : "r" (func), "r" (edx) - : "edx", "ecx", "cc", "memory"); + : "edx", "cc", "memory"); return eax; } -// Call a 16bit SeaBIOS function, restoring the mode from last call32(). -static u32 -call16_back(u32 eax, u32 edx, void *func) -{ - ASSERT32FLAT(); - if (CONFIG_CALL32_SMM && Call32Data.method == C32_SMM) - return call16_smm(eax, edx, func); - if (Call32Data.method == C32_SLOPPY) - return call16_sloppy(eax, edx, func); - if (in_post()) - return call16big(eax, edx, func); - return call16(eax, edx, func); -} - /**************************************************************** * Extra 16bit stack @@ -398,7 +328,7 @@ on_extra_stack(void) // Switch to the extra stack and call a function. u32 -stack_hop(u32 eax, u32 edx, void *func) +__stack_hop(u32 eax, u32 edx, void *func) { if (on_extra_stack()) return ((u32 (*)(u32, u32))func)(eax, edx); @@ -431,10 +361,10 @@ stack_hop(u32 eax, u32 edx, void *func) // Switch back to original caller's stack and call a function. u32 -stack_hop_back(u32 eax, u32 edx, void *func) +__stack_hop_back(u32 eax, u32 edx, void *func) { if (!MODESEGMENT) - return call16_back(eax, edx, func); + return call16(eax, edx, func); if (!MODE16 || !on_extra_stack()) return ((u32 (*)(u32, u32))func)(eax, edx); ASSERT16(); @@ -474,8 +404,7 @@ void VISIBLE16 _farcall16(struct bregs *callregs, u16 callregseg) { if (need_hop_back()) { - extern void _cfunc16__farcall16(void); - stack_hop_back((u32)callregs, callregseg, _cfunc16__farcall16); + stack_hop_back(_farcall16, callregs, callregseg); return; } ASSERT16(); @@ -486,18 +415,20 @@ _farcall16(struct bregs *callregs, u16 callregseg) : "ebx", "ecx", "esi", "edi", "cc", "memory"); } +// Invoke external 16bit code. void farcall16(struct bregs *callregs) { - extern void _cfunc16__farcall16(void); - call16((u32)callregs, 0, _cfunc16__farcall16); + call16_override(0); + _farcall16(callregs, 0); } +// Invoke external 16bit code in "big real" mode. void farcall16big(struct bregs *callregs) { - extern void _cfunc16__farcall16(void); - call16big((u32)callregs, 0, _cfunc16__farcall16); + call16_override(1); + _farcall16(callregs, 0); } // Invoke a 16bit software interrupt. @@ -507,7 +438,7 @@ __call16_int(struct bregs *callregs, u16 offset) callregs->code.offset = offset; if (!MODESEGMENT) { callregs->code.seg = SEG_BIOS; - _farcall16((void*)callregs - Call32Data.ss * 16, Call32Data.ss); + _farcall16((void*)callregs - Call16Data.ss * 16, Call16Data.ss); return; } callregs->code.seg = GET_SEG(CS); @@ -520,7 +451,7 @@ reset(void) { extern void reset_vector(void) __noreturn; if (!MODE16) - call16_back(0, 0, reset_vector); + call16(0, 0, reset_vector); reset_vector(); } @@ -558,12 +489,13 @@ getCurThread(void) return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE); } -static int ThreadControl; +static u8 CanInterrupt, ThreadControl; // Initialize the support for internal threads. void -thread_init(void) +thread_setup(void) { + CanInterrupt = 1; if (! CONFIG_THREADS) return; ThreadControl = romfile_loadint("etc/threads", 1); @@ -573,7 +505,7 @@ thread_init(void) int threads_during_optionroms(void) { - return CONFIG_THREADS && ThreadControl == 2 && in_post(); + return CONFIG_THREADS && CONFIG_RTC_TIMER && ThreadControl == 2 && in_post(); } // Switch to next thread stack. @@ -660,11 +592,17 @@ fail: void VISIBLE16 check_irqs(void) { + if (!MODESEGMENT && !CanInterrupt) { + // Can't enable interrupts (PIC and/or IVT not yet setup) + cpu_relax(); + return; + } if (need_hop_back()) { - extern void _cfunc16_check_irqs(void); - stack_hop_back(0, 0, _cfunc16_check_irqs); + stack_hop_back(check_irqs, 0, 0); return; } + if (MODE16) + clock_poll_irq(); asm volatile("sti ; nop ; rep ; nop ; cli ; cld" : : :"memory"); } @@ -689,8 +627,7 @@ void VISIBLE16 wait_irq(void) { if (need_hop_back()) { - extern void _cfunc16_wait_irq(void); - stack_hop_back(0, 0, _cfunc16_wait_irq); + stack_hop_back(wait_irq, 0, 0); return; } asm volatile("sti ; hlt ; cli ; cld": : :"memory"); @@ -700,8 +637,9 @@ wait_irq(void) void yield_toirq(void) { - if (!MODESEGMENT && have_threads()) { - // Threads still active - do a yield instead. + if (!CONFIG_HARDWARE_IRQ + || (!MODESEGMENT && (have_threads() || !CanInterrupt))) { + // Threads still active or irqs not available - do a yield instead. yield(); return; } @@ -794,9 +732,8 @@ yield_preempt(void) void check_preempt(void) { - extern void _cfunc32flat_yield_preempt(void); if (CONFIG_THREADS && GET_GLOBAL(CanPreempt) && have_threads()) - call32(_cfunc32flat_yield_preempt, 0, 0); + call32(yield_preempt, 0, 0); } @@ -817,11 +754,10 @@ call32_params_helper(struct call32_params_s *params) } u32 -call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret) +__call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret) { ASSERT16(); struct call32_params_s params = {func, eax, edx, ecx}; - extern void _cfunc32flat_call32_params_helper(void); - return call32(_cfunc32flat_call32_params_helper - , (u32)MAKE_FLATPTR(GET_SEG(SS), ¶ms), errret); + return call32(call32_params_helper, MAKE_FLATPTR(GET_SEG(SS), ¶ms) + , errret); } diff --git a/roms/seabios/src/stacks.h b/roms/seabios/src/stacks.h index 82c4c3c85..c71bdc8e3 100644 --- a/roms/seabios/src/stacks.h +++ b/roms/seabios/src/stacks.h @@ -10,17 +10,27 @@ // stacks.c extern int HaveSmmCall32; -u32 call32(void *func, u32 eax, u32 errret); +u32 __call32(void *func, u32 eax, u32 errret); +#define call32(func, eax, errret) ({ \ + extern void _cfunc32flat_ ##func (void); \ + __call32( _cfunc32flat_ ##func , (u32)(eax), (errret)); \ + }) extern u8 ExtraStack[], *StackPos; -u32 stack_hop(u32 eax, u32 edx, void *func); -u32 stack_hop_back(u32 eax, u32 edx, void *func); +u32 __stack_hop(u32 eax, u32 edx, void *func); +#define stack_hop(func, eax, edx) \ + __stack_hop((u32)(eax), (u32)(edx), (func)) +u32 __stack_hop_back(u32 eax, u32 edx, void *func); +#define stack_hop_back(func, eax, edx) ({ \ + extern void _cfunc16_ ##func (void); \ + __stack_hop_back((u32)(eax), (u32)(edx), _cfunc16_ ##func ); \ + }) int on_extra_stack(void); struct bregs; void farcall16(struct bregs *callregs); void farcall16big(struct bregs *callregs); void __call16_int(struct bregs *callregs, u16 offset); #define call16_int(nr, callregs) do { \ - extern void irq_trampoline_ ##nr (); \ + extern void irq_trampoline_ ##nr (void); \ __call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \ } while (0) void reset(void); @@ -28,7 +38,7 @@ extern struct thread_info MainThread; struct thread_info *getCurThread(void); void yield(void); void yield_toirq(void); -void thread_init(void); +void thread_setup(void); int threads_during_optionroms(void); void run_thread(void (*func)(void*), void *data); void wait_threads(void); @@ -39,7 +49,12 @@ void start_preempt(void); void finish_preempt(void); int wait_preempt(void); void check_preempt(void); -u32 call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret); +u32 __call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret); +#define call32_params(func, eax, edx, ecx, errret) ({ \ + extern void _cfunc32flat_ ##func (void); \ + __call32_params( _cfunc32flat_ ##func , (u32)(eax), (u32)(edx) \ + , (u32)(ecx), (errret)); \ + }) // Inline functions diff --git a/roms/seabios/src/std/acpi.h b/roms/seabios/src/std/acpi.h index e0d9516ba..b672bbee4 100644 --- a/roms/seabios/src/std/acpi.h +++ b/roms/seabios/src/std/acpi.h @@ -294,4 +294,24 @@ struct acpi_table_mcfg { struct acpi_mcfg_allocation allocation[0]; } PACKED; + +struct rsdt_descriptor { + ACPI_TABLE_HEADER_DEF + u32 entry[1]; +} PACKED; + +#define TCPA_SIGNATURE 0x41504354 +struct tcpa_descriptor_rev2 +{ + ACPI_TABLE_HEADER_DEF + u16 platform_class; + u32 log_area_minimum_length; + u64 log_area_start_address; +} PACKED; + +/* TCPA ACPI definitions */ +#define TCPA_ACPI_CLASS_CLIENT 0 +#define TCPA_ACPI_CLASS_SERVER 1 + + #endif // acpi.h diff --git a/roms/seabios/src/std/bda.h b/roms/seabios/src/std/bda.h index c321266e2..4ad6605d4 100644 --- a/roms/seabios/src/std/bda.h +++ b/roms/seabios/src/std/bda.h @@ -7,7 +7,7 @@ /**************************************************************** - * Interupt vector table + * Interrupt vector table ****************************************************************/ struct rmode_IVT { diff --git a/roms/seabios/src/std/multiboot.h b/roms/seabios/src/std/multiboot.h new file mode 100644 index 000000000..6c9512703 --- /dev/null +++ b/roms/seabios/src/std/multiboot.h @@ -0,0 +1,260 @@ +/* multiboot.h - Multiboot header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 + +/* The magic field should contain this. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000004 + +/* Flags set in the 'flags' member of the multiboot header. */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +/* Flags to be set in the 'flags' member of the multiboot info structure. */ + +/* is there basic lower/upper memory information? */ +#define MULTIBOOT_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MULTIBOOT_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MULTIBOOT_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MULTIBOOT_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 + +/* is there a full memory map? */ +#define MULTIBOOT_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MULTIBOOT_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 + +#ifndef ASM_FILE + +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* Feature flags. */ + multiboot_uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; + multiboot_uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + multiboot_uint32_t mode_type; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +/* The symbol table for a.out. */ +struct multiboot_aout_symbol_table +{ + multiboot_uint32_t tabsize; + multiboot_uint32_t strsize; + multiboot_uint32_t addr; + multiboot_uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +/* The section header table for ELF. */ +struct multiboot_elf_section_header_table +{ + multiboot_uint32_t num; + multiboot_uint32_t size; + multiboot_uint32_t addr; + multiboot_uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + +struct multiboot_info +{ + /* Multiboot info version number */ + multiboot_uint32_t flags; + + /* Available memory from BIOS */ + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; + + /* "root" partition */ + multiboot_uint32_t boot_device; + + /* Kernel command line */ + multiboot_uint32_t cmdline; + + /* Boot-Module list */ + multiboot_uint32_t mods_count; + multiboot_uint32_t mods_addr; + + union + { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /* Memory Mapping buffer */ + multiboot_uint32_t mmap_length; + multiboot_uint32_t mmap_addr; + + /* Drive Info buffer */ + multiboot_uint32_t drives_length; + multiboot_uint32_t drives_addr; + + /* ROM configuration table */ + multiboot_uint32_t config_table; + + /* Boot Loader Name */ + multiboot_uint32_t boot_loader_name; + + /* APM table */ + multiboot_uint32_t apm_table; + + /* Video */ + multiboot_uint32_t vbe_control_info; + multiboot_uint32_t vbe_mode_info; + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + multiboot_uint32_t size; + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + multiboot_uint32_t type; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_mod_list +{ + /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + + /* Module command line */ + multiboot_uint32_t cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + multiboot_uint32_t pad; +}; +typedef struct multiboot_mod_list multiboot_module_t; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ diff --git a/roms/seabios/src/std/smbios.h b/roms/seabios/src/std/smbios.h index 05137167a..4ccf2ea34 100644 --- a/roms/seabios/src/std/smbios.h +++ b/roms/seabios/src/std/smbios.h @@ -3,11 +3,13 @@ #include "types.h" // u32 +#define SMBIOS_SIGNATURE 0x5f4d535f // "_SM_" + /* SMBIOS entry point -- must be written to a 16-bit aligned address between 0xf0000 and 0xfffff. */ struct smbios_entry_point { - char anchor_string[4]; + u32 signature; u8 checksum; u8 length; u8 smbios_major_version; diff --git a/roms/seabios/src/string.c b/roms/seabios/src/string.c index 2e4e43746..adb8198f8 100644 --- a/roms/seabios/src/string.c +++ b/roms/seabios/src/string.c @@ -227,7 +227,7 @@ strtcpy(char *dest, const char *src, size_t len) return dest; } -// locate first occurance of character c in the string s +// locate first occurrence of character c in the string s char * strchr(const char *s, int c) { diff --git a/roms/seabios/src/string.h b/roms/seabios/src/string.h index a557d6a44..d069989db 100644 --- a/roms/seabios/src/string.h +++ b/roms/seabios/src/string.h @@ -11,12 +11,12 @@ size_t strlen(const char *s); int memcmp_far(u16 s1seg, const void *s1, u16 s2seg, const void *s2, size_t n); int memcmp(const void *s1, const void *s2, size_t n); int strcmp(const char *s1, const char *s2); -inline void memset_far(u16 d_seg, void *d_far, u8 c, size_t len); -inline void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len); +void memset_far(u16 d_seg, void *d_far, u8 c, size_t len); +void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len); void *memset(void *s, int c, size_t n); void memset_fl(void *ptr, u8 val, size_t size); -inline void memcpy_far(u16 d_seg, void *d_far - , u16 s_seg, const void *s_far, size_t len); +void memcpy_far(u16 d_seg, void *d_far + , u16 s_seg, const void *s_far, size_t len); void memcpy_fl(void *d_fl, const void *s_fl, size_t len); void *memcpy(void *d1, const void *s1, size_t len); #if MODESEGMENT == 0 diff --git a/roms/seabios/src/system.c b/roms/seabios/src/system.c index 60a6fce58..438e60e2c 100644 --- a/roms/seabios/src/system.c +++ b/roms/seabios/src/system.c @@ -7,9 +7,9 @@ #include "biosvar.h" // GET_GLOBAL #include "bregs.h" // struct bregs +#include "e820map.h" // E820_RAM #include "hw/pic.h" // pic_reset #include "malloc.h" // LegacyRamSize -#include "memmap.h" // E820_RAM #include "output.h" // debug_enter #include "string.h" // memcpy_far #include "util.h" // handle_1553 diff --git a/roms/seabios/src/tcgbios.c b/roms/seabios/src/tcgbios.c new file mode 100644 index 000000000..09954825c --- /dev/null +++ b/roms/seabios/src/tcgbios.c @@ -0,0 +1,1480 @@ +// Implementation of the TCG BIOS extension according to the specification +// described in specs found at +// http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios +// +// Copyright (C) 2006-2011, 2014, 2015 IBM Corporation +// +// Authors: +// Stefan Berger <stefanb@linux.vnet.ibm.com> +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + + +#include "config.h" + +#include "types.h" +#include "byteorder.h" // cpu_to_* +#include "hw/tpm_drivers.h" // tpm_drivers[] +#include "farptr.h" // MAKE_FLATPTR +#include "string.h" // checksum +#include "tcgbios.h"// tpm_*, prototypes +#include "util.h" // printf, get_keystroke +#include "output.h" // dprintf +#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor +#include "bregs.h" // struct bregs +#include "sha1.h" // sha1 +#include "fw/paravirt.h" // runningOnXen +#include "std/smbios.h" + +static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR }; +static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE }; + +static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 }; +static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 }; +static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 }; +static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 }; + +static const u8 CommandFlag_FALSE[1] = { 0x00 }; +static const u8 CommandFlag_TRUE[1] = { 0x01 }; + +static const u8 GetCapability_Permanent_Flags[] = { + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x08 +}; + +static const u8 GetCapability_OwnerAuth[] = { + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x11 +}; + +static const u8 GetCapability_Timeouts[] = { + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x15 +}; + +static const u8 GetCapability_Durations[] = { + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x01, 0x20 +}; + +static u8 evt_separator[] = {0xff,0xff,0xff,0xff}; + + +#define RSDP_CAST(ptr) ((struct rsdp_descriptor *)ptr) + +/* local function prototypes */ + +static u32 tpm_calling_int19h(void); +static u32 tpm_add_event_separators(void); +static u32 tpm_start_option_rom_scan(void); +static u32 tpm_smbios_measure(void); + +/* helper functions */ + +static inline void *input_buf32(struct bregs *regs) +{ + return MAKE_FLATPTR(regs->es, regs->di); +} + +static inline void *output_buf32(struct bregs *regs) +{ + return MAKE_FLATPTR(regs->ds, regs->si); +} + + +typedef struct { + u8 tpm_probed:1; + u8 tpm_found:1; + u8 tpm_working:1; + u8 if_shutdown:1; + u8 tpm_driver_to_use:4; +} tpm_state_t; + + +static tpm_state_t tpm_state = { + .tpm_driver_to_use = TPM_INVALID_DRIVER, +}; + + +/******************************************************** + Extensions for TCG-enabled BIOS + *******************************************************/ + + +static u32 +is_tpm_present(void) +{ + u32 rc = 0; + unsigned int i; + + for (i = 0; i < TPM_NUM_DRIVERS; i++) { + struct tpm_driver *td = &tpm_drivers[i]; + if (td->probe() != 0) { + td->init(); + tpm_state.tpm_driver_to_use = i; + rc = 1; + break; + } + } + + return rc; +} + +static void +probe_tpm(void) +{ + if (!tpm_state.tpm_probed) { + tpm_state.tpm_probed = 1; + tpm_state.tpm_found = (is_tpm_present() != 0); + tpm_state.tpm_working = tpm_state.tpm_found; + } +} + +static int +has_working_tpm(void) +{ + probe_tpm(); + + return tpm_state.tpm_working; +} + +static struct tcpa_descriptor_rev2 * +find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp) +{ + u32 ctr = 0; + struct tcpa_descriptor_rev2 *tcpa = NULL; + struct rsdt_descriptor *rsdt; + u32 length; + u16 off; + + rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address; + if (!rsdt) + return NULL; + + length = rsdt->length; + off = offsetof(struct rsdt_descriptor, entry); + + while ((off + sizeof(rsdt->entry[0])) <= length) { + /* try all pointers to structures */ + tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr]; + + /* valid TCPA ACPI table ? */ + if (tcpa->signature == TCPA_SIGNATURE && + checksum((u8 *)tcpa, tcpa->length) == 0) + break; + + tcpa = NULL; + off += sizeof(rsdt->entry[0]); + ctr++; + } + + return tcpa; +} + + +static struct tcpa_descriptor_rev2 * +find_tcpa_table(void) +{ + struct tcpa_descriptor_rev2 *tcpa = NULL; + struct rsdp_descriptor *rsdp = RsdpAddr; + + if (rsdp) + tcpa = find_tcpa_by_rsdp(rsdp); + else + tpm_state.if_shutdown = 1; + + if (!rsdp) + dprintf(DEBUG_tcg, + "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n"); + else if (!tcpa) + dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n"); + + return tcpa; +} + + +static u8 * +get_lasa_base_ptr(u32 *log_area_minimum_length) +{ + u8 *log_area_start_address = 0; + struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table(); + + if (tcpa) { + log_area_start_address = (u8 *)(long)tcpa->log_area_start_address; + if (log_area_minimum_length) + *log_area_minimum_length = tcpa->log_area_minimum_length; + } + + return log_area_start_address; +} + + +/* clear the ACPI log */ +static void +reset_acpi_log(void) +{ + u32 log_area_minimum_length; + u8 *log_area_start_address = get_lasa_base_ptr(&log_area_minimum_length); + + if (log_area_start_address) + memset(log_area_start_address, 0x0, log_area_minimum_length); +} + + +/* + initialize the TCPA ACPI subsystem; find the ACPI tables and determine + where the TCPA table is. + */ +static void +tpm_acpi_init(void) +{ + tpm_state.if_shutdown = 0; + tpm_state.tpm_probed = 0; + tpm_state.tpm_found = 0; + tpm_state.tpm_working = 0; + + if (!has_working_tpm()) { + tpm_state.if_shutdown = 1; + return; + } + + reset_acpi_log(); +} + + +static u32 +transmit(u8 locty, const struct iovec iovec[], + u8 *respbuffer, u32 *respbufferlen, + enum tpmDurationType to_t) +{ + u32 rc = 0; + u32 irc; + struct tpm_driver *td; + unsigned int i; + + if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER) + return TCG_FATAL_COM_ERROR; + + td = &tpm_drivers[tpm_state.tpm_driver_to_use]; + + irc = td->activate(locty); + if (irc != 0) { + /* tpm could not be activated */ + return TCG_FATAL_COM_ERROR; + } + + for (i = 0; iovec[i].length; i++) { + irc = td->senddata(iovec[i].data, + iovec[i].length); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + } + + irc = td->waitdatavalid(); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + + irc = td->waitrespready(to_t); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + + irc = td->readresp(respbuffer, + respbufferlen); + if (irc != 0) + return TCG_FATAL_COM_ERROR; + + td->ready(); + + return rc; +} + + +/* + * Send a TPM command with the given ordinal. Append the given buffer + * containing all data in network byte order to the command (this is + * the custom part per command) and expect a response of the given size. + * If a buffer is provided, the response will be copied into it. + */ +static u32 +build_and_send_cmd_od(u8 locty, u32 ordinal, const u8 *append, u32 append_size, + u8 *resbuffer, u32 return_size, u32 *returnCode, + const u8 *otherdata, u32 otherdata_size, + enum tpmDurationType to_t) +{ +#define MAX_APPEND_SIZE sizeof(GetCapability_Timeouts) +#define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags) + u32 rc; + u8 ibuffer[TPM_REQ_HEADER_SIZE + MAX_APPEND_SIZE]; + u8 obuffer[MAX_RESPONSE_SIZE]; + struct tpm_req_header *trqh = (struct tpm_req_header *)ibuffer; + struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer; + struct iovec iovec[3]; + u32 obuffer_len = sizeof(obuffer); + u32 idx = 1; + + if (append_size > MAX_APPEND_SIZE || + return_size > MAX_RESPONSE_SIZE) { + dprintf(DEBUG_tcg, "TCGBIOS: size of requested buffers too big."); + return TCG_FIRMWARE_ERROR; + } + + iovec[0].data = trqh; + iovec[0].length = TPM_REQ_HEADER_SIZE + append_size; + + if (otherdata) { + iovec[1].data = (void *)otherdata; + iovec[1].length = otherdata_size; + idx = 2; + } + + iovec[idx].data = NULL; + iovec[idx].length = 0; + + memset(ibuffer, 0x0, sizeof(ibuffer)); + memset(obuffer, 0x0, sizeof(obuffer)); + + trqh->tag = cpu_to_be16(TPM_TAG_RQU_CMD); + trqh->totlen = cpu_to_be32(TPM_REQ_HEADER_SIZE + append_size + + otherdata_size); + trqh->ordinal = cpu_to_be32(ordinal); + + if (append_size) + memcpy((char *)trqh + sizeof(*trqh), + append, append_size); + + rc = transmit(locty, iovec, obuffer, &obuffer_len, to_t); + if (rc) + return rc; + + *returnCode = be32_to_cpu(trsh->errcode); + + if (resbuffer) + memcpy(resbuffer, trsh, return_size); + + return 0; +} + + +static u32 +build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size, + u8 *resbuffer, u32 return_size, u32 *returnCode, + enum tpmDurationType to_t) +{ + return build_and_send_cmd_od(locty, ordinal, append, append_size, + resbuffer, return_size, returnCode, + NULL, 0, to_t); +} + + +static u32 +determine_timeouts(void) +{ + u32 rc; + u32 returnCode; + struct tpm_res_getcap_timeouts timeouts; + struct tpm_res_getcap_durations durations; + struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use]; + u32 i; + + rc = build_and_send_cmd(0, TPM_ORD_GetCapability, + GetCapability_Timeouts, + sizeof(GetCapability_Timeouts), + (u8 *)&timeouts, sizeof(timeouts), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)" + " = 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(0, TPM_ORD_GetCapability, + GetCapability_Durations, + sizeof(GetCapability_Durations), + (u8 *)&durations, sizeof(durations), + &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)" + " = 0x%08x\n", returnCode); + + if (rc || returnCode) + goto err_exit; + + for (i = 0; i < 3; i++) + durations.durations[i] = be32_to_cpu(durations.durations[i]); + + for (i = 0; i < 4; i++) + timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]); + + dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n", + timeouts.timeouts[0], + timeouts.timeouts[1], + timeouts.timeouts[2], + timeouts.timeouts[3]); + + dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n", + durations.durations[0], + durations.durations[1], + durations.durations[2]); + + + td->set_timeouts(timeouts.timeouts, durations.durations); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +tpm_startup(void) +{ + u32 rc; + u32 returnCode; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n"); + rc = build_and_send_cmd(0, TPM_ORD_Startup, + Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR), + NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n", + returnCode); + + if (CONFIG_COREBOOT) { + /* with other firmware on the system the TPM may already have been + * initialized + */ + if (returnCode == TPM_INVALID_POSTINIT) + returnCode = 0; + } + + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0, + NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG); + + dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n", + returnCode); + + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0, + NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n", + returnCode); + + if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY)) + goto err_exit; + + rc = determine_timeouts(); + if (rc) + goto err_exit; + + rc = tpm_smbios_measure(); + if (rc) + goto err_exit; + + rc = tpm_start_option_rom_scan(); + if (rc) + goto err_exit; + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +void +tpm_setup(void) +{ + if (!CONFIG_TCGBIOS) + return; + + tpm_acpi_init(); + if (runningOnXen()) + return; + + tpm_startup(); +} + + +void +tpm_prepboot(void) +{ + u32 rc; + u32 returnCode; + + if (!CONFIG_TCGBIOS) + return; + + if (!has_working_tpm()) + return; + + rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_CMD_ENABLE, + sizeof(PhysicalPresence_CMD_ENABLE), + NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); + if (rc || returnCode) + goto err_exit; + + rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence, + PhysicalPresence_NOT_PRESENT_LOCK, + sizeof(PhysicalPresence_NOT_PRESENT_LOCK), + NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); + if (rc || returnCode) + goto err_exit; + + rc = tpm_calling_int19h(); + if (rc) + goto err_exit; + + rc = tpm_add_event_separators(); + if (rc) + goto err_exit; + + return; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; +} + +static int +is_valid_pcpes(struct pcpes *pcpes) +{ + return (pcpes->eventtype != 0); +} + + +static u8 * +get_lasa_last_ptr(u16 *entry_count, u8 **log_area_start_address_next) +{ + struct pcpes *pcpes; + u32 log_area_minimum_length = 0; + u8 *log_area_start_address_base = + get_lasa_base_ptr(&log_area_minimum_length); + u8 *log_area_start_address_last = NULL; + u8 *end = log_area_start_address_base + log_area_minimum_length; + u32 size; + + if (entry_count) + *entry_count = 0; + + if (!log_area_start_address_base) + return NULL; + + while (log_area_start_address_base < end) { + pcpes = (struct pcpes *)log_area_start_address_base; + if (!is_valid_pcpes(pcpes)) + break; + if (entry_count) + (*entry_count)++; + size = pcpes->eventdatasize + offsetof(struct pcpes, event); + log_area_start_address_last = log_area_start_address_base; + log_area_start_address_base += size; + } + + if (log_area_start_address_next) + *log_area_start_address_next = log_area_start_address_base; + + return log_area_start_address_last; +} + + +static u32 +tpm_sha1_calc(const u8 *data, u32 length, u8 *hash) +{ + u32 rc; + u32 returnCode; + struct tpm_res_sha1start start; + struct tpm_res_sha1complete complete; + u32 blocks = length / 64; + u32 rest = length & 0x3f; + u32 numbytes, numbytes_no; + u32 offset = 0; + + rc = build_and_send_cmd(0, TPM_ORD_SHA1Start, + NULL, 0, + (u8 *)&start, sizeof(start), + &returnCode, TPM_DURATION_TYPE_SHORT); + + if (rc || returnCode) + goto err_exit; + + while (blocks > 0) { + + numbytes = be32_to_cpu(start.max_num_bytes); + if (numbytes > blocks * 64) + numbytes = blocks * 64; + + numbytes_no = cpu_to_be32(numbytes); + + rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Update, + (u8 *)&numbytes_no, sizeof(numbytes_no), + NULL, 0, &returnCode, + &data[offset], numbytes, + TPM_DURATION_TYPE_SHORT); + + if (rc || returnCode) + goto err_exit; + + offset += numbytes; + blocks -= (numbytes / 64); + } + + numbytes_no = cpu_to_be32(rest); + + rc = build_and_send_cmd_od(0, TPM_ORD_SHA1Complete, + (u8 *)&numbytes_no, sizeof(numbytes_no), + (u8 *)&complete, sizeof(complete), + &returnCode, + &data[offset], rest, TPM_DURATION_TYPE_SHORT); + + if (rc || returnCode) + goto err_exit; + + memcpy(hash, complete.hash, sizeof(complete.hash)); + + return 0; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM SHA1 malfunctioning.\n"); + + tpm_state.tpm_working = 0; + if (rc) + return rc; + return TCG_TCG_COMMAND_ERROR; +} + + +static u32 +sha1_calc(const u8 *data, u32 length, u8 *hash) +{ + if (length < tpm_drivers[tpm_state.tpm_driver_to_use].sha1threshold) + return tpm_sha1_calc(data, length, hash); + + return sha1(data, length, hash); +} + + +/* + * Extend the ACPI log with the given entry by copying the + * entry data into the log. + * Input + * Pointer to the structure to be copied into the log + * + * Output: + * lower 16 bits of return code contain entry number + * if entry number is '0', then upper 16 bits contain error code. + */ +static u32 +tpm_extend_acpi_log(void *entry_ptr, u16 *entry_count) +{ + u32 log_area_minimum_length, size; + u8 *log_area_start_address_base = + get_lasa_base_ptr(&log_area_minimum_length); + u8 *log_area_start_address_next = NULL; + struct pcpes *pcpes = (struct pcpes *)entry_ptr; + + get_lasa_last_ptr(entry_count, &log_area_start_address_next); + + dprintf(DEBUG_tcg, "TCGBIOS: LASA_BASE = %p, LASA_NEXT = %p\n", + log_area_start_address_base, log_area_start_address_next); + + if (log_area_start_address_next == NULL || log_area_minimum_length == 0) + return TCG_PC_LOGOVERFLOW; + + size = pcpes->eventdatasize + offsetof(struct pcpes, event); + + if ((log_area_start_address_next + size - log_area_start_address_base) > + log_area_minimum_length) { + dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size); + return TCG_PC_LOGOVERFLOW; + } + + memcpy(log_area_start_address_next, entry_ptr, size); + + (*entry_count)++; + + return 0; +} + + +static u32 +is_preboot_if_shutdown(void) +{ + return tpm_state.if_shutdown; +} + + +static u32 +shutdown_preboot_interface(void) +{ + u32 rc = 0; + + if (!is_preboot_if_shutdown()) { + tpm_state.if_shutdown = 1; + } else { + rc = TCG_INTERFACE_SHUTDOWN; + } + + return rc; +} + + +static void +tpm_shutdown(void) +{ + reset_acpi_log(); + shutdown_preboot_interface(); +} + + +static u32 +pass_through_to_tpm(struct pttti *pttti, struct pttto *pttto) +{ + u32 rc = 0; + u32 resbuflen = 0; + struct tpm_req_header *trh; + u8 locty = 0; + struct iovec iovec[2]; + const u32 *tmp; + + if (is_preboot_if_shutdown()) { + rc = TCG_INTERFACE_SHUTDOWN; + goto err_exit; + } + + trh = (struct tpm_req_header *)pttti->tpmopin; + + if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE || + pttti->opblength < sizeof(struct pttto) || + be32_to_cpu(trh->totlen) + sizeof(struct pttti) > pttti->ipblength ) { + rc = TCG_INVALID_INPUT_PARA; + goto err_exit; + } + + resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout); + + iovec[0].data = pttti->tpmopin; + tmp = (const u32 *)&((u8 *)iovec[0].data)[2]; + iovec[0].length = cpu_to_be32(*tmp); + + iovec[1].data = NULL; + iovec[1].length = 0; + + rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen, + TPM_DURATION_TYPE_LONG /* worst case */); + if (rc) + goto err_exit; + + pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen; + pttto->reserved = 0; + +err_exit: + if (rc != 0) { + pttto->opblength = 4; + pttto->reserved = 0; + } + + return rc; +} + + +static u32 +tpm_extend(u8 *hash, u32 pcrindex) +{ + u32 rc; + struct pttto_extend pttto; + struct pttti_extend pttti = { + .pttti = { + .ipblength = sizeof(struct pttti_extend), + .opblength = sizeof(struct pttto_extend), + }, + .req = { + .tag = cpu_to_be16(0xc1), + .totlen = cpu_to_be32(sizeof(pttti.req)), + .ordinal = cpu_to_be32(TPM_ORD_Extend), + .pcrindex = cpu_to_be32(pcrindex), + }, + }; + + memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest)); + + rc = pass_through_to_tpm(&pttti.pttti, &pttto.pttto); + + if (rc == 0) { + if (pttto.pttto.opblength < TPM_RSP_HEADER_SIZE || + pttto.pttto.opblength != + sizeof(struct pttto) + be32_to_cpu(pttto.rsp.totlen) || + be16_to_cpu(pttto.rsp.tag) != 0xc4) { + rc = TCG_FATAL_COM_ERROR; + } + } + + if (rc) + tpm_shutdown(); + + return rc; +} + + +static u32 +hash_all(const struct hai *hai, u8 *hash) +{ + if (is_preboot_if_shutdown() != 0) + return TCG_INTERFACE_SHUTDOWN; + + if (hai->ipblength != sizeof(struct hai) || + hai->hashdataptr == 0 || + hai->hashdatalen == 0 || + hai->algorithmid != TPM_ALG_SHA) + return TCG_INVALID_INPUT_PARA; + + return sha1_calc((const u8 *)hai->hashdataptr, hai->hashdatalen, hash); +} + + +static u32 +hash_log_event(const struct hlei *hlei, struct hleo *hleo) +{ + u32 rc = 0; + u16 size; + struct pcpes *pcpes; + u16 entry_count; + + if (is_preboot_if_shutdown() != 0) { + rc = TCG_INTERFACE_SHUTDOWN; + goto err_exit; + } + + size = hlei->ipblength; + if (size != sizeof(*hlei)) { + rc = TCG_INVALID_INPUT_PARA; + goto err_exit; + } + + pcpes = (struct pcpes *)hlei->logdataptr; + + if (pcpes->pcrindex >= 24 || + pcpes->pcrindex != hlei->pcrindex || + pcpes->eventtype != hlei->logeventtype) { + rc = TCG_INVALID_INPUT_PARA; + goto err_exit; + } + + if ((hlei->hashdataptr != 0) && (hlei->hashdatalen != 0)) { + rc = sha1_calc((const u8 *)hlei->hashdataptr, + hlei->hashdatalen, pcpes->digest); + if (rc) + return rc; + } + + rc = tpm_extend_acpi_log((void *)hlei->logdataptr, &entry_count); + if (rc) + goto err_exit; + + /* updating the log was fine */ + hleo->opblength = sizeof(struct hleo); + hleo->reserved = 0; + hleo->eventnumber = entry_count; + +err_exit: + if (rc != 0) { + hleo->opblength = 2; + hleo->reserved = 0; + } + + return rc; +} + + +static u32 +hash_log_extend_event(const struct hleei_short *hleei_s, struct hleeo *hleeo) +{ + u32 rc = 0; + struct hleo hleo; + struct hleei_long *hleei_l = (struct hleei_long *)hleei_s; + const void *logdataptr; + u32 logdatalen; + struct pcpes *pcpes; + + /* short or long version? */ + switch (hleei_s->ipblength) { + case sizeof(struct hleei_short): + /* short */ + logdataptr = hleei_s->logdataptr; + logdatalen = hleei_s->logdatalen; + break; + + case sizeof(struct hleei_long): + /* long */ + logdataptr = hleei_l->logdataptr; + logdatalen = hleei_l->logdatalen; + break; + + default: + /* bad input block */ + rc = TCG_INVALID_INPUT_PARA; + goto err_exit; + } + + pcpes = (struct pcpes *)logdataptr; + + struct hlei hlei = { + .ipblength = sizeof(hlei), + .hashdataptr = hleei_s->hashdataptr, + .hashdatalen = hleei_s->hashdatalen, + .pcrindex = hleei_s->pcrindex, + .logeventtype= pcpes->eventtype, + .logdataptr = logdataptr, + .logdatalen = logdatalen, + }; + + rc = hash_log_event(&hlei, &hleo); + if (rc) + goto err_exit; + + hleeo->opblength = sizeof(struct hleeo); + hleeo->reserved = 0; + hleeo->eventnumber = hleo.eventnumber; + + rc = tpm_extend(pcpes->digest, hleei_s->pcrindex); + +err_exit: + if (rc != 0) { + hleeo->opblength = 4; + hleeo->reserved = 0; + } + + return rc; + +} + + +static u32 +tss(struct ti *ti, struct to *to) +{ + u32 rc = 0; + + if (is_preboot_if_shutdown() == 0) { + rc = TCG_PC_UNSUPPORTED; + } else { + rc = TCG_INTERFACE_SHUTDOWN; + } + + to->opblength = sizeof(struct to); + to->reserved = 0; + + return rc; +} + + +static u32 +compact_hash_log_extend_event(u8 *buffer, + u32 info, + u32 length, + u32 pcrindex, + u32 *edx_ptr) +{ + u32 rc = 0; + struct hleeo hleeo; + struct pcpes pcpes = { + .pcrindex = pcrindex, + .eventtype = EV_COMPACT_HASH, + .eventdatasize = sizeof(info), + .event = info, + }; + struct hleei_short hleei = { + .ipblength = sizeof(hleei), + .hashdataptr = buffer, + .hashdatalen = length, + .pcrindex = pcrindex, + .logdataptr = &pcpes, + .logdatalen = sizeof(pcpes), + }; + + rc = hash_log_extend_event(&hleei, &hleeo); + if (rc == 0) + *edx_ptr = hleeo.eventnumber; + + return rc; +} + + +void VISIBLE32FLAT +tpm_interrupt_handler32(struct bregs *regs) +{ + if (!CONFIG_TCGBIOS) + return; + + set_cf(regs, 0); + + if (!has_working_tpm()) { + regs->eax = TCG_GENERAL_ERROR; + return; + } + + switch ((enum irq_ids)regs->al) { + case TCG_StatusCheck: + if (is_tpm_present() == 0) { + /* no TPM available */ + regs->eax = TCG_PC_TPM_NOT_PRESENT; + } else { + regs->eax = 0; + regs->ebx = TCG_MAGIC; + regs->ch = TCG_VERSION_MAJOR; + regs->cl = TCG_VERSION_MINOR; + regs->edx = 0x0; + regs->esi = (u32)get_lasa_base_ptr(NULL); + regs->edi = + (u32)get_lasa_last_ptr(NULL, NULL); + } + break; + + case TCG_HashLogExtendEvent: + regs->eax = + hash_log_extend_event( + (struct hleei_short *)input_buf32(regs), + (struct hleeo *)output_buf32(regs)); + break; + + case TCG_PassThroughToTPM: + regs->eax = + pass_through_to_tpm((struct pttti *)input_buf32(regs), + (struct pttto *)output_buf32(regs)); + break; + + case TCG_ShutdownPreBootInterface: + regs->eax = shutdown_preboot_interface(); + break; + + case TCG_HashLogEvent: + regs->eax = hash_log_event((struct hlei*)input_buf32(regs), + (struct hleo*)output_buf32(regs)); + break; + + case TCG_HashAll: + regs->eax = + hash_all((struct hai*)input_buf32(regs), + (u8 *)output_buf32(regs)); + break; + + case TCG_TSS: + regs->eax = tss((struct ti*)input_buf32(regs), + (struct to*)output_buf32(regs)); + break; + + case TCG_CompactHashLogExtendEvent: + regs->eax = + compact_hash_log_extend_event((u8 *)input_buf32(regs), + regs->esi, + regs->ecx, + regs->edx, + ®s->edx); + break; + + default: + set_cf(regs, 1); + } + + return; +} + +/* + * Add a measurement to the log; the data at data_seg:data/length are + * appended to the TCG_PCClientPCREventStruct + * + * Input parameters: + * pcrIndex : which PCR to extend + * event_type : type of event; specs section on 'Event Types' + * info : pointer to info (e.g., string) to be added to log as-is + * info_length: length of the info + * data : pointer to the data (i.e., string) to be added to the log + * data_length: length of the data + */ +static u32 +tpm_add_measurement_to_log(u32 pcrIndex, u32 event_type, + const char *info, u32 info_length, + const u8 *data, u32 data_length) +{ + u32 rc = 0; + struct hleeo hleeo; + u8 _pcpes[offsetof(struct pcpes, event) + 400]; + struct pcpes *pcpes = (struct pcpes *)_pcpes; + + if (info_length < sizeof(_pcpes) - offsetof(struct pcpes, event)) { + + pcpes->pcrindex = pcrIndex; + pcpes->eventtype = event_type; + memset(&pcpes->digest, 0x0, sizeof(pcpes->digest)); + pcpes->eventdatasize = info_length; + memcpy(&pcpes->event, info, info_length); + + struct hleei_short hleei = { + .ipblength = sizeof(hleei), + .hashdataptr = data, + .hashdatalen = data_length, + .pcrindex = pcrIndex, + .logdataptr = _pcpes, + .logdatalen = info_length + offsetof(struct pcpes, event), + }; + + rc = hash_log_extend_event(&hleei, &hleeo); + } else { + rc = TCG_GENERAL_ERROR; + } + + return rc; +} + + +/* + * Add a measurement to the list of measurements + * pcrIndex : PCR to be extended + * event_type : type of event; specs section on 'Event Types' + * data : additional parameter; used as parameter for + * 'action index' + */ +static u32 +tpm_add_measurement(u32 pcrIndex, + u16 event_type, + const char *string) +{ + u32 rc; + u32 len; + + switch (event_type) { + case EV_SEPARATOR: + len = sizeof(evt_separator); + rc = tpm_add_measurement_to_log(pcrIndex, event_type, + (char *)NULL, 0, + (u8 *)evt_separator, len); + break; + + case EV_ACTION: + rc = tpm_add_measurement_to_log(pcrIndex, event_type, + string, strlen(string), + (u8 *)string, strlen(string)); + break; + + default: + rc = TCG_INVALID_INPUT_PARA; + } + + return rc; +} + + +static u32 +tpm_calling_int19h(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + return tpm_add_measurement(4, EV_ACTION, + "Calling INT 19h"); +} + +/* + * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events' + */ +u32 +tpm_add_event_separators(void) +{ + u32 rc; + u32 pcrIndex = 0; + + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + while (pcrIndex <= 7) { + rc = tpm_add_measurement(pcrIndex, EV_SEPARATOR, NULL); + if (rc) + break; + pcrIndex ++; + } + + return rc; +} + + +/* + * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to + * the list of measurements. + */ +static u32 +tpm_add_bootdevice(u32 bootcd, u32 bootdrv) +{ + const char *string; + + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + switch (bootcd) { + case 0: + switch (bootdrv) { + case 0: + string = "Booting BCV device 00h (Floppy)"; + break; + + case 0x80: + string = "Booting BCV device 80h (HDD)"; + break; + + default: + string = "Booting unknown device"; + break; + } + + break; + + default: + string = "Booting from CD ROM device"; + } + + return tpm_add_measurement_to_log(4, EV_ACTION, + string, strlen(string), + (u8 *)string, strlen(string)); +} + + +/* + * Add measurement to the log about option rom scan + */ +u32 +tpm_start_option_rom_scan(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + return tpm_add_measurement(2, EV_ACTION, + "Start Option ROM Scan"); +} + + +/* + * Add measurement to the log about an option rom + */ +u32 +tpm_option_rom(const void *addr, u32 len) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc; + struct pcctes_romex pcctes = { + .eventid = 7, + .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE, + }; + + rc = sha1((const u8 *)addr, len, pcctes.digest); + if (rc) + return rc; + + return tpm_add_measurement_to_log(2, + EV_EVENT_TAG, + (const char *)&pcctes, sizeof(pcctes), + (u8 *)&pcctes, sizeof(pcctes)); +} + + +u32 +tpm_smbios_measure(void) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc; + struct pcctes pcctes = { + .eventid = 1, + .eventdatasize = SHA1_BUFSIZE, + }; + struct smbios_entry_point *sep = SMBiosAddr; + + dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep); + + if (!sep) + return 0; + + rc = sha1((const u8 *)sep->structure_table_address, + sep->structure_table_length, pcctes.digest); + if (rc) + return rc; + + return tpm_add_measurement_to_log(1, + EV_EVENT_TAG, + (const char *)&pcctes, sizeof(pcctes), + (u8 *)&pcctes, sizeof(pcctes)); +} + + +/* + * Add a measurement related to Initial Program Loader to the log. + * Creates two log entries. + * + * Input parameter: + * bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito + * addr : address where the IP data are located + * length : IP data length in bytes + */ +static u32 +tpm_ipl(enum ipltype bootcd, const u8 *addr, u32 length) +{ + u32 rc; + const char *string; + + switch (bootcd) { + case IPL_EL_TORITO_1: + /* specs: see section 'El Torito' */ + string = "EL TORITO IPL"; + rc = tpm_add_measurement_to_log(4, EV_IPL, + string, strlen(string), + addr, length); + break; + + case IPL_EL_TORITO_2: + /* specs: see section 'El Torito' */ + string = "BOOT CATALOG"; + rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA, + string, strlen(string), + addr, length); + break; + + default: + /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */ + /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */ + string = "MBR"; + rc = tpm_add_measurement_to_log(4, EV_IPL, + string, strlen(string), + addr, 0x1b8); + + if (rc) + break; + + /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */ + string = "MBR PARTITION_TABLE"; + rc = tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA, + string, strlen(string), + addr + 0x1b8, 0x48); + } + + return rc; +} + +u32 +tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc = tpm_add_bootdevice(0, bootdrv); + if (rc) + return rc; + + return tpm_ipl(IPL_BCV, addr, length); +} + +u32 +tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc = tpm_add_bootdevice(1, bootdrv); + if (rc) + return rc; + + return tpm_ipl(IPL_EL_TORITO_1, addr, length); +} + +u32 +tpm_add_cdrom_catalog(const u8 *addr, u32 length) +{ + if (!CONFIG_TCGBIOS) + return 0; + + if (!has_working_tpm()) + return TCG_GENERAL_ERROR; + + u32 rc = tpm_add_bootdevice(1, 0); + if (rc) + return rc; + + return tpm_ipl(IPL_EL_TORITO_2, addr, length); +} + +void +tpm_s3_resume(void) +{ + u32 rc; + u32 returnCode; + + if (!CONFIG_TCGBIOS) + return; + + if (!has_working_tpm()) + return; + + dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n"); + + rc = build_and_send_cmd(0, TPM_ORD_Startup, + Startup_ST_STATE, sizeof(Startup_ST_STATE), + NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT); + + dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n", + returnCode); + + if (rc || returnCode) + goto err_exit; + + return; + +err_exit: + dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__); + + tpm_state.tpm_working = 0; +} diff --git a/roms/seabios/src/tcgbios.h b/roms/seabios/src/tcgbios.h new file mode 100644 index 000000000..4b7eaabef --- /dev/null +++ b/roms/seabios/src/tcgbios.h @@ -0,0 +1,375 @@ +#ifndef TCGBIOS_H +#define TCGBIOS_H + +#include "types.h" + +/* Define for section 12.3 */ +#define TCG_PC_OK 0x0 +#define TCG_PC_TPMERROR 0x1 +#define TCG_PC_LOGOVERFLOW 0x2 +#define TCG_PC_UNSUPPORTED 0x3 + +#define TPM_ALG_SHA 0x4 + +#define TCG_MAGIC 0x41504354L +#define TCG_VERSION_MAJOR 1 +#define TCG_VERSION_MINOR 2 + +#define TPM_OK 0x0 +#define TPM_RET_BASE 0x1 +#define TCG_GENERAL_ERROR (TPM_RET_BASE + 0x0) +#define TCG_TPM_IS_LOCKED (TPM_RET_BASE + 0x1) +#define TCG_NO_RESPONSE (TPM_RET_BASE + 0x2) +#define TCG_INVALID_RESPONSE (TPM_RET_BASE + 0x3) +#define TCG_INVALID_ACCESS_REQUEST (TPM_RET_BASE + 0x4) +#define TCG_FIRMWARE_ERROR (TPM_RET_BASE + 0x5) +#define TCG_INTEGRITY_CHECK_FAILED (TPM_RET_BASE + 0x6) +#define TCG_INVALID_DEVICE_ID (TPM_RET_BASE + 0x7) +#define TCG_INVALID_VENDOR_ID (TPM_RET_BASE + 0x8) +#define TCG_UNABLE_TO_OPEN (TPM_RET_BASE + 0x9) +#define TCG_UNABLE_TO_CLOSE (TPM_RET_BASE + 0xa) +#define TCG_RESPONSE_TIMEOUT (TPM_RET_BASE + 0xb) +#define TCG_INVALID_COM_REQUEST (TPM_RET_BASE + 0xc) +#define TCG_INVALID_ADR_REQUEST (TPM_RET_BASE + 0xd) +#define TCG_WRITE_BYTE_ERROR (TPM_RET_BASE + 0xe) +#define TCG_READ_BYTE_ERROR (TPM_RET_BASE + 0xf) +#define TCG_BLOCK_WRITE_TIMEOUT (TPM_RET_BASE + 0x10) +#define TCG_CHAR_WRITE_TIMEOUT (TPM_RET_BASE + 0x11) +#define TCG_CHAR_READ_TIMEOUT (TPM_RET_BASE + 0x12) +#define TCG_BLOCK_READ_TIMEOUT (TPM_RET_BASE + 0x13) +#define TCG_TRANSFER_ABORT (TPM_RET_BASE + 0x14) +#define TCG_INVALID_DRV_FUNCTION (TPM_RET_BASE + 0x15) +#define TCG_OUTPUT_BUFFER_TOO_SHORT (TPM_RET_BASE + 0x16) +#define TCG_FATAL_COM_ERROR (TPM_RET_BASE + 0x17) +#define TCG_INVALID_INPUT_PARA (TPM_RET_BASE + 0x18) +#define TCG_TCG_COMMAND_ERROR (TPM_RET_BASE + 0x19) +#define TCG_INTERFACE_SHUTDOWN (TPM_RET_BASE + 0x20) +//define TCG_PC_UNSUPPORTED (TPM_RET_BASE + 0x21) +#define TCG_PC_TPM_NOT_PRESENT (TPM_RET_BASE + 0x22) +#define TCG_PC_TPM_DEACTIVATED (TPM_RET_BASE + 0x23) + + +#define TPM_ORD_SelfTestFull 0x00000050 +#define TPM_ORD_ForceClear 0x0000005d +#define TPM_ORD_GetCapability 0x00000065 +#define TPM_ORD_PhysicalEnable 0x0000006f +#define TPM_ORD_PhysicalDisable 0x00000070 +#define TPM_ORD_SetOwnerInstall 0x00000071 +#define TPM_ORD_PhysicalSetDeactivated 0x00000072 +#define TPM_ORD_Startup 0x00000099 +#define TPM_ORD_PhysicalPresence 0x4000000a +#define TPM_ORD_Extend 0x00000014 +#define TPM_ORD_SHA1Start 0x000000a0 +#define TPM_ORD_SHA1Update 0x000000a1 +#define TPM_ORD_SHA1Complete 0x000000a2 +#define TSC_ORD_ResetEstablishmentBit 0x4000000b + + +#define TPM_ST_CLEAR 0x1 +#define TPM_ST_STATE 0x2 +#define TPM_ST_DEACTIVATED 0x3 + + +/* TPM command error codes */ +#define TPM_INVALID_POSTINIT 0x26 +#define TPM_BAD_LOCALITY 0x3d + +/* TPM command tags */ +#define TPM_TAG_RQU_CMD 0x00c1 + +/* interrupt identifiers (al register) */ +enum irq_ids { + TCG_StatusCheck = 0, + TCG_HashLogExtendEvent = 1, + TCG_PassThroughToTPM = 2, + TCG_ShutdownPreBootInterface = 3, + TCG_HashLogEvent = 4, + TCG_HashAll = 5, + TCG_TSS = 6, + TCG_CompactHashLogExtendEvent = 7, +}; + +/* event types: 10.4.1 / table 11 */ +#define EV_POST_CODE 1 +#define EV_SEPARATOR 4 +#define EV_ACTION 5 +#define EV_EVENT_TAG 6 +#define EV_COMPACT_HASH 12 +#define EV_IPL 13 +#define EV_IPL_PARTITION_DATA 14 + + +#define STATUS_FLAG_SHUTDOWN (1 << 0) + +#define SHA1_BUFSIZE 20 + + +struct iovec +{ + size_t length; + void *data; +}; + + +/* Input and Output blocks for the TCG BIOS commands */ + +struct hleei_short +{ + u16 ipblength; + u16 reserved; + const void *hashdataptr; + u32 hashdatalen; + u32 pcrindex; + const void *logdataptr; + u32 logdatalen; +} PACKED; + + +struct hleei_long +{ + u16 ipblength; + u16 reserved; + void *hashdataptr; + u32 hashdatalen; + u32 pcrindex; + u32 reserved2; + void *logdataptr; + u32 logdatalen; +} PACKED; + + +struct hleeo +{ + u16 opblength; + u16 reserved; + u32 eventnumber; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +struct pttti +{ + u16 ipblength; + u16 reserved; + u16 opblength; + u16 reserved2; + u8 tpmopin[0]; +} PACKED; + + +struct pttto +{ + u16 opblength; + u16 reserved; + u8 tpmopout[0]; +}; + + +struct hlei +{ + u16 ipblength; + u16 reserved; + const void *hashdataptr; + u32 hashdatalen; + u32 pcrindex; + u32 logeventtype; + const void *logdataptr; + u32 logdatalen; +} PACKED; + + +struct hleo +{ + u16 opblength; + u16 reserved; + u32 eventnumber; +} PACKED; + + +struct hai +{ + u16 ipblength; + u16 reserved; + const void *hashdataptr; + u32 hashdatalen; + u32 algorithmid; +} PACKED; + + +struct ti +{ + u16 ipblength; + u16 reserved; + u16 opblength; + u16 reserved2; + u8 tssoperandin[0]; +} PACKED; + + +struct to +{ + u16 opblength; + u16 reserved; + u8 tssoperandout[0]; +} PACKED; + + +struct pcpes +{ + u32 pcrindex; + u32 eventtype; + u8 digest[SHA1_BUFSIZE]; + u32 eventdatasize; + u32 event; +} PACKED; + +struct pcctes +{ + u32 eventid; + u32 eventdatasize; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + +struct pcctes_romex +{ + u32 eventid; + u32 eventdatasize; + u16 reserved; + u16 pfa; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +#define TPM_REQ_HEADER \ + u16 tag; \ + u32 totlen; \ + u32 ordinal; + +#define TPM_REQ_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32)) + +#define TPM_RSP_HEADER \ + u16 tag; \ + u32 totlen; \ + u32 errcode; + +#define TPM_RSP_HEADER_SIZE (sizeof(u16) + sizeof(u32) + sizeof(u32)) + +struct tpm_req_header { + TPM_REQ_HEADER; +} PACKED; + + +struct tpm_rsp_header { + TPM_RSP_HEADER; +} PACKED; + + +struct tpm_req_extend { + TPM_REQ_HEADER + u32 pcrindex; + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +struct tpm_rsp_extend { + TPM_RSP_HEADER + u8 digest[SHA1_BUFSIZE]; +} PACKED; + + +struct tpm_req_getcap_perm_flags { + TPM_REQ_HEADER + u32 capArea; + u32 subCapSize; + u32 subCap; +} PACKED; + + +struct tpm_permanent_flags { + u16 tag; + u8 flags[20]; +} PACKED; + + +enum permFlagsIndex { + PERM_FLAG_IDX_DISABLE = 0, + PERM_FLAG_IDX_OWNERSHIP, + PERM_FLAG_IDX_DEACTIVATED, + PERM_FLAG_IDX_READPUBEK, + PERM_FLAG_IDX_DISABLEOWNERCLEAR, + PERM_FLAG_IDX_ALLOW_MAINTENANCE, + PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK, + PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE, +}; + + +struct tpm_res_getcap_perm_flags { + TPM_RSP_HEADER + u32 size; + struct tpm_permanent_flags perm_flags; +} PACKED; + + +struct tpm_res_getcap_ownerauth { + TPM_RSP_HEADER + u32 size; + u8 flag; +} PACKED; + + +struct tpm_res_getcap_timeouts { + TPM_RSP_HEADER + u32 size; + u32 timeouts[4]; +} PACKED; + + +struct tpm_res_getcap_durations { + TPM_RSP_HEADER + u32 size; + u32 durations[3]; +} PACKED; + + +struct tpm_res_sha1start { + TPM_RSP_HEADER + u32 max_num_bytes; +} PACKED; + + +struct tpm_res_sha1complete { + TPM_RSP_HEADER + u8 hash[20]; +} PACKED; + +struct pttti_extend { + struct pttti pttti; + struct tpm_req_extend req; +} PACKED; + + +struct pttto_extend { + struct pttto pttto; + struct tpm_rsp_extend rsp; +} PACKED; + + +enum ipltype { + IPL_BCV = 0, + IPL_EL_TORITO_1, + IPL_EL_TORITO_2 +}; + + +struct bregs; +void tpm_interrupt_handler32(struct bregs *regs); + +void tpm_setup(void); +void tpm_prepboot(void); +void tpm_s3_resume(void); +u32 tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length); +u32 tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length); +u32 tpm_add_cdrom_catalog(const u8 *addr, u32 length); +u32 tpm_option_rom(const void *addr, u32 len); + +#endif /* TCGBIOS_H */ diff --git a/roms/seabios/src/types.h b/roms/seabios/src/types.h index 097372cdb..19d9f6c14 100644 --- a/roms/seabios/src/types.h +++ b/roms/seabios/src/types.h @@ -70,7 +70,7 @@ extern void __force_link_error__only_in_16bit(void) __noreturn; # define VARFSEG __section(".discard.varfseg." UNIQSEC) __VISIBLE __weak // Designate a variable at a specific address in the f-segment. # define VARFSEGFIXED(addr) __section(".discard.varfixed." UNIQSEC) __VISIBLE __weak -// Verify a variable is only accessable via 32bit "init" functions +// Verify a variable is only accessible via 32bit "init" functions # define VARVERIFY32INIT __section(".discard.varinit." UNIQSEC) // Designate top-level assembler as 16bit only. # define ASM16(code) __ASM(code) diff --git a/roms/seabios/src/util.h b/roms/seabios/src/util.h index 09bb8a9f3..cba3359d5 100644 --- a/roms/seabios/src/util.h +++ b/roms/seabios/src/util.h @@ -43,17 +43,17 @@ void enable_bootsplash(void); void disable_bootsplash(void); // cdrom.c -extern u8 CDRom_locks[]; extern struct eltorito_s CDEmu; extern struct drive_s *cdemu_drive_gf; struct disk_op_s; -int process_cdemu_op(struct disk_op_s *op); +int cdemu_process_op(struct disk_op_s *op); void cdrom_prepboot(void); int cdrom_boot(struct drive_s *drive_g); // clock.c void clock_setup(void); void handle_1583(struct bregs *regs); +void clock_poll_irq(void); u32 irqtimer_calc_ticks(u32 count); u32 irqtimer_calc(u32 msecs); int irqtimer_check(u32 end); @@ -75,6 +75,7 @@ u32 find_resume_vector(void); void acpi_reboot(void); void find_acpi_features(void); extern struct smbios_entry_point *SMBiosAddr; +struct smbios_entry_point *get_smbios_entry_point(); void copy_smbios(void *pos); void display_uuid(void); void copy_table(void *pos); @@ -104,6 +105,9 @@ void mptable_setup(void); // fw/mtrr.c void mtrr_setup(void); +// fw/multiboot.c +void multiboot_init(void); + // fw/pciinit.c extern const u8 pci_irqs[4]; void pci_setup(void); @@ -139,15 +143,15 @@ extern struct floppy_ext_dbt_s diskette_param_table2; void floppy_setup(void); struct drive_s *init_floppy(int floppyid, int ftype); int find_floppy_type(u32 size); -int process_floppy_op(struct disk_op_s *op); +int floppy_process_op(struct disk_op_s *op); void floppy_tick(void); // hw/ramdisk.c void ramdisk_setup(void); -int process_ramdisk_op(struct disk_op_s *op); +int ramdisk_process_op(struct disk_op_s *op); // hw/sdcard.c -int process_sdcard_op(struct disk_op_s *op); +int sdcard_process_op(struct disk_op_s *op); void sdcard_setup(void); // hw/timer.c @@ -232,6 +236,6 @@ void vgahook_setup(struct pci_device *pci); // version (auto generated file out/version.c) -extern const char VERSION[]; +extern const char VERSION[], BUILDINFO[]; #endif // util.h diff --git a/roms/seabios/src/version.c b/roms/seabios/src/version.c new file mode 100644 index 000000000..a8a58cf09 --- /dev/null +++ b/roms/seabios/src/version.c @@ -0,0 +1,5 @@ +// Place build generated version into a C variable +#include "autoversion.h" + +char VERSION[] = BUILD_VERSION; +char BUILDINFO[] = BUILD_TOOLS; diff --git a/roms/seabios/src/vgahooks.c b/roms/seabios/src/vgahooks.c index 6a4acfeaf..48efb086c 100644 --- a/roms/seabios/src/vgahooks.c +++ b/roms/seabios/src/vgahooks.c @@ -124,7 +124,7 @@ getAMDRamSpeed(void) /* int 0x15 - 5f18 - ECX = unknown/dont care + ECX = unknown/don't care EBX[3..0] Frame Buffer Size 2^N MiB EBX[7..4] Memory speed: 0: SDR 66Mhz diff --git a/roms/seabios/src/x86.h b/roms/seabios/src/x86.h index 7798b1c17..53378e9ed 100644 --- a/roms/seabios/src/x86.h +++ b/roms/seabios/src/x86.h @@ -75,14 +75,22 @@ static inline void __cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) : "0" (index)); } -static inline u32 getcr0(void) { +static inline u32 cr0_read(void) { u32 cr0; asm("movl %%cr0, %0" : "=r"(cr0)); return cr0; } -static inline void setcr0(u32 cr0) { +static inline void cr0_write(u32 cr0) { asm("movl %0, %%cr0" : : "r"(cr0)); } +static inline void cr0_mask(u32 off, u32 on) { + cr0_write((cr0_read() & ~off) | on); +} +static inline u16 cr0_vm86_read(void) { + u16 cr0; + asm("smsww %0" : "=r"(cr0)); + return cr0; +} static inline u64 rdmsr(u32 index) { @@ -124,6 +132,13 @@ static inline u32 getesp(void) { return esp; } +static inline u32 rol(u32 val, u16 rol) { + u32 res; + asm volatile("roll %%cl, %%eax" + : "=a" (res) : "a" (val), "c" (rol)); + return res; +} + static inline void outb(u8 value, u16 port) { __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port)); } @@ -175,6 +190,14 @@ static inline void outsl(u16 port, u32 *data, u32 count) { : "+c"(count), "+S"(data) : "d"(port) : "memory"); } +/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */ +static inline void smp_rmb(void) { + barrier(); +} +static inline void smp_wmb(void) { + barrier(); +} + static inline void writel(void *addr, u32 val) { barrier(); *(volatile u32 *)addr = val; diff --git a/roms/seabios/vgasrc/Kconfig b/roms/seabios/vgasrc/Kconfig index 91d590ae2..f5098a4bd 100644 --- a/roms/seabios/vgasrc/Kconfig +++ b/roms/seabios/vgasrc/Kconfig @@ -58,6 +58,25 @@ menu "VGA ROM" endchoice choice + depends on VGA_BOCHS + prompt "bochs vga variant" + default VGA_BOCHS_STDVGA + + config VGA_BOCHS_STDVGA + bool "qemu stdvga / bochs svga" + + config VGA_BOCHS_VMWARE + bool "qemu vmware svga" + + config VGA_BOCHS_QXL + bool "qemu qxl vga" + + config VGA_BOCHS_VIRTIO + bool "qemu virtio vga" + + endchoice + + choice depends on VGA_GEODEGX2 || VGA_GEODELX prompt "Output Mode" default VGA_OUTPUT_CRT @@ -141,7 +160,10 @@ menu "VGA ROM" hex prompt "PCI Vendor ID" if OVERRIDE_PCI_ID default 0x1013 if VGA_CIRRUS - default 0x1234 if VGA_BOCHS + default 0x1234 if VGA_BOCHS_STDVGA + default 0x15ad if VGA_BOCHS_VMWARE + default 0x1b36 if VGA_BOCHS_QXL + default 0x1af4 if VGA_BOCHS_VIRTIO default 0x100b if VGA_GEODEGX2 default 0x1022 if VGA_GEODELX default 0x0000 @@ -153,7 +175,10 @@ menu "VGA ROM" hex prompt "PCI Vendor ID" if OVERRIDE_PCI_ID default 0x00b8 if VGA_CIRRUS - default 0x1111 if VGA_BOCHS + default 0x1111 if VGA_BOCHS_STDVGA + default 0x0405 if VGA_BOCHS_VMWARE + default 0x0100 if VGA_BOCHS_QXL + default 0x1050 if VGA_BOCHS_VIRTIO default 0x0030 if VGA_GEODEGX2 default 0x2081 if VGA_GEODELX default 0x0000 diff --git a/roms/seabios/vgasrc/geodevga.h b/roms/seabios/vgasrc/geodevga.h index 61d78084d..c99f54bb1 100644 --- a/roms/seabios/vgasrc/geodevga.h +++ b/roms/seabios/vgasrc/geodevga.h @@ -2,7 +2,7 @@ // // Copyright (C) 2009 Chris Kindt // -// Writen for Google Summer of Code 2009 for the coreboot project +// Written for Google Summer of Code 2009 for the coreboot project // // This file may be distributed under the terms of the GNU LGPLv3 license. diff --git a/roms/seabios/vgasrc/vgabios.c b/roms/seabios/vgasrc/vgabios.c index 4aa50e1c1..f07e85bd3 100644 --- a/roms/seabios/vgasrc/vgabios.c +++ b/roms/seabios/vgasrc/vgabios.c @@ -304,6 +304,12 @@ vga_set_mode(int mode, int flags) SET_BDA(video_mode, 0xff); SET_BDA_EXT(vbe_mode, mode | (flags & MF_VBEFLAGS)); SET_BDA_EXT(vgamode_offset, (u32)vmode_g); + if (CONFIG_VGA_ALLOCATE_EXTRA_STACK) + // Disable extra stack if it appears a modern OS is in use. + // This works around bugs in some versions of Windows (Vista + // and possibly later) when the stack is in the e-segment. + MASK_BDA_EXT(flags, BF_EXTRA_STACK + , (flags & MF_LEGACY) ? BF_EXTRA_STACK : 0); if (memmodel == MM_TEXT) { SET_BDA(video_cols, width); SET_BDA(video_rows, height-1); diff --git a/roms/seabios/vgasrc/vgabios.h b/roms/seabios/vgasrc/vgabios.h index fd796f2e6..831f69407 100644 --- a/roms/seabios/vgasrc/vgabios.h +++ b/roms/seabios/vgasrc/vgabios.h @@ -62,7 +62,8 @@ struct gfx_op { #define GO_MEMSET 3 #define GO_MEMMOVE 4 -// Custom internal storage in BDA +// Custom internal storage in BDA (don't change here without also +// updating vgaentry.S) #define VGA_CUSTOM_BDA 0xb9 struct vga_bda_s { @@ -74,6 +75,7 @@ struct vga_bda_s { #define BF_PM_MASK 0x0f #define BF_EMULATE_TEXT 0x10 #define BF_SWCURSOR 0x20 +#define BF_EXTRA_STACK 0x40 #define GET_BDA_EXT(var) \ GET_FARVAR(SEG_BDA, ((struct vga_bda_s *)VGA_CUSTOM_BDA)->var) diff --git a/roms/seabios/vgasrc/vgaentry.S b/roms/seabios/vgasrc/vgaentry.S index d9ebdb93c..53be2b38c 100644 --- a/roms/seabios/vgasrc/vgaentry.S +++ b/roms/seabios/vgasrc/vgaentry.S @@ -86,14 +86,23 @@ entry_10: ENTRY_ARG_VGA handle_10 iretw +#define VGA_CUSTOM_BDA_FLAGS 0xb9 +#define BF_EXTRA_STACK 0x40 + // Entry point using extra stack DECLFUNC entry_10_extrastack entry_10_extrastack: cli cld - pushw %ds // Set %ds:%eax to space on ExtraStack + pushw %ds pushl %eax - movw %cs:ExtraStackSeg, %ds + + movw $SEG_BDA, %ax // Check if extra stack is enabled + movw %ax, %ds + testb $BF_EXTRA_STACK, VGA_CUSTOM_BDA_FLAGS + jz 1f + + movw %cs:ExtraStackSeg, %ds // Set %ds:%eax to space on ExtraStack movl $(CONFIG_VGA_EXTRA_STACK_SIZE-PUSHBREGS_size-16), %eax SAVEBREGS_POP_DSEAX // Save registers on extra stack movl %esp, PUSHBREGS_size+8(%eax) @@ -116,6 +125,11 @@ entry_10_extrastack: RESTOREBREGS_DSEAX iretw +1: // Use regular entry point if the extra stack is disabled + popl %eax + popw %ds + jmp entry_10 + // Timer irq handling DECLFUNC entry_timer_hook entry_timer_hook: diff --git a/roms/seabios/vgasrc/vgafb.c b/roms/seabios/vgasrc/vgafb.c index 1a94fcf70..5d1ecc936 100644 --- a/roms/seabios/vgasrc/vgafb.c +++ b/roms/seabios/vgasrc/vgafb.c @@ -273,28 +273,22 @@ gfx_direct(struct gfx_op *op) int bypp = DIV_ROUND_UP(depth, 8); void *dest_far = (fb + op->displaystart + op->y * op->linelength + op->x * bypp); + u8 data[64]; + int i; switch (op->op) { default: - case GO_READ8: { - u8 data[64]; + case GO_READ8: memcpy_high(MAKE_FLATPTR(GET_SEG(SS), data), dest_far, bypp * 8); - int i; for (i=0; i<8; i++) op->pixels[i] = reverse_color(depth, *(u32*)&data[i*bypp]); break; - } - case GO_WRITE8: { - u8 data[64]; - int i; + case GO_WRITE8: for (i=0; i<8; i++) *(u32*)&data[i*bypp] = get_color(depth, op->pixels[i]); memcpy_high(dest_far, MAKE_FLATPTR(GET_SEG(SS), data), bypp * 8); break; - } - case GO_MEMSET: { + case GO_MEMSET: ; u32 color = get_color(depth, op->pixels[0]); - u8 data[64]; - int i; for (i=0; i<8; i++) *(u32*)&data[i*bypp] = color; memcpy_high(dest_far, MAKE_FLATPTR(GET_SEG(SS), data), bypp * 8); @@ -303,7 +297,6 @@ gfx_direct(struct gfx_op *op) memcpy_high(dest_far + op->linelength * i , dest_far, op->xlen * bypp); break; - } case GO_MEMMOVE: ; void *src_far = (fb + op->displaystart + op->srcy * op->linelength + op->x * bypp); diff --git a/roms/seabios/vgasrc/vgainit.c b/roms/seabios/vgasrc/vgainit.c index 8d1226182..40997dbbd 100644 --- a/roms/seabios/vgasrc/vgainit.c +++ b/roms/seabios/vgasrc/vgainit.c @@ -150,6 +150,7 @@ vga_post(struct bregs *regs) { serial_debug_preinit(); dprintf(1, "Start SeaVGABIOS (version %s)\n", VERSION); + dprintf(1, "VGABUILD: %s\n", BUILDINFO); debug_enter(regs, DEBUG_VGA_POST); if (CONFIG_VGA_PCI && !GET_GLOBAL(HaveRunInit)) { diff --git a/roms/seabios/vgasrc/vgaversion.c b/roms/seabios/vgasrc/vgaversion.c new file mode 100644 index 000000000..1ef5ddb79 --- /dev/null +++ b/roms/seabios/vgasrc/vgaversion.c @@ -0,0 +1,6 @@ +// Place build generated version into a C variable +#include "autovgaversion.h" +#include "types.h" + +char VERSION[] VAR16 = BUILD_VERSION; +char BUILDINFO[] VAR16 = BUILD_TOOLS; |