diff options
author | 2016-06-03 03:33:22 +0000 | |
---|---|---|
committer | 2016-06-03 03:33:23 +0000 | |
commit | da27230f80795d0028333713f036d44c53cb0e68 (patch) | |
tree | b3d379eaf000adf72b36cb01cdf4d79c3e3f064c /qemu/roms/seabios | |
parent | 0e68cb048bb8aadb14675f5d4286d8ab2fc35449 (diff) | |
parent | 437fd90c0250dee670290f9b714253671a990160 (diff) |
Merge "These changes are the raw update to qemu-2.6."
Diffstat (limited to 'qemu/roms/seabios')
125 files changed, 5788 insertions, 1631 deletions
diff --git a/qemu/roms/seabios/.version b/qemu/roms/seabios/.version index a96337339..89c0c6acb 100644 --- a/qemu/roms/seabios/.version +++ b/qemu/roms/seabios/.version @@ -1 +1 @@ -rel-1.8.2-0-g33fbe13 +rel-1.9.1-0-gb3ef39f diff --git a/qemu/roms/seabios/Makefile b/qemu/roms/seabios/Makefile index 83cdff377..4e4092d07 100644 --- a/qemu/roms/seabios/Makefile +++ b/qemu/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/qemu/roms/seabios/docs/Build_overview.md b/qemu/roms/seabios/docs/Build_overview.md index 26db22691..8c6b2f458 100644 --- a/qemu/roms/seabios/docs/Build_overview.md +++ b/qemu/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/qemu/roms/seabios/docs/Contributing.md b/qemu/roms/seabios/docs/Contributing.md new file mode 100644 index 000000000..d0f2b5b5e --- /dev/null +++ b/qemu/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/qemu/roms/seabios/docs/Debugging.md b/qemu/roms/seabios/docs/Debugging.md index 03567de4d..7ab5d02d8 100644 --- a/qemu/roms/seabios/docs/Debugging.md +++ b/qemu/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/qemu/roms/seabios/docs/Developer_Documentation.md b/qemu/roms/seabios/docs/Developer_Documentation.md index d50455d36..24bf48a3e 100644 --- a/qemu/roms/seabios/docs/Developer_Documentation.md +++ b/qemu/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/qemu/roms/seabios/docs/Download.md b/qemu/roms/seabios/docs/Download.md index a49c6fb74..9b1492ac5 100644 --- a/qemu/roms/seabios/docs/Download.md +++ b/qemu/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/qemu/roms/seabios/docs/Execution_and_code_flow.md b/qemu/roms/seabios/docs/Execution_and_code_flow.md index 9396ecaa4..a54776eef 100644 --- a/qemu/roms/seabios/docs/Execution_and_code_flow.md +++ b/qemu/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/qemu/roms/seabios/docs/Linking_overview.md b/qemu/roms/seabios/docs/Linking_overview.md index fb938b632..bcb8298c3 100644 --- a/qemu/roms/seabios/docs/Linking_overview.md +++ b/qemu/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/qemu/roms/seabios/docs/Releases.md b/qemu/roms/seabios/docs/Releases.md index 6a1ecd564..c24d3c0b7 100644 --- a/qemu/roms/seabios/docs/Releases.md +++ b/qemu/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/qemu/roms/seabios/docs/Runtime_config.md b/qemu/roms/seabios/docs/Runtime_config.md new file mode 100644 index 000000000..d6fea2827 --- /dev/null +++ b/qemu/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/qemu/roms/seabios/docs/SeaBIOS.md b/qemu/roms/seabios/docs/SeaBIOS.md index 831bfced9..e24913a64 100644 --- a/qemu/roms/seabios/docs/SeaBIOS.md +++ b/qemu/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/qemu/roms/seabios/docs/SeaVGABIOS.md b/qemu/roms/seabios/docs/SeaVGABIOS.md new file mode 100644 index 000000000..7ec27804d --- /dev/null +++ b/qemu/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/qemu/roms/seabios/scripts/buildversion.py b/qemu/roms/seabios/scripts/buildversion.py new file mode 100755 index 000000000..46928984e --- /dev/null +++ b/qemu/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/qemu/roms/seabios/scripts/buildversion.sh b/qemu/roms/seabios/scripts/buildversion.sh deleted file mode 100755 index 516aff5b2..000000000 --- a/qemu/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/qemu/roms/seabios/scripts/checkrom.py b/qemu/roms/seabios/scripts/checkrom.py index 377277db5..aced5e2cf 100755 --- a/qemu/roms/seabios/scripts/checkrom.py +++ b/qemu/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/qemu/roms/seabios/scripts/checkstack.py b/qemu/roms/seabios/scripts/checkstack.py index b49b6c8cc..5d9b0bfaf 100755 --- a/qemu/roms/seabios/scripts/checkstack.py +++ b/qemu/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/qemu/roms/seabios/scripts/kconfig/lxdialog/util.c b/qemu/roms/seabios/scripts/kconfig/lxdialog/util.c index f7abdeb92..2a0d182e8 100644 --- a/qemu/roms/seabios/scripts/kconfig/lxdialog/util.c +++ b/qemu/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/qemu/roms/seabios/scripts/layoutrom.py b/qemu/roms/seabios/scripts/layoutrom.py index dd770fe49..b976fb056 100755 --- a/qemu/roms/seabios/scripts/layoutrom.py +++ b/qemu/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/qemu/roms/seabios/src/Kconfig b/qemu/roms/seabios/src/Kconfig index 45ca59cf3..95bf087b8 100644 --- a/qemu/roms/seabios/src/Kconfig +++ b/qemu/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/qemu/roms/seabios/src/biosvar.h b/qemu/roms/seabios/src/biosvar.h index 58bcbcedb..f61fb6a50 100644 --- a/qemu/roms/seabios/src/biosvar.h +++ b/qemu/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/qemu/roms/seabios/src/block.c b/qemu/roms/seabios/src/block.c index 3f7ecb1d7..1762e2a33 100644 --- a/qemu/roms/seabios/src/block.c +++ b/qemu/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/qemu/roms/seabios/src/block.h b/qemu/roms/seabios/src/block.h index 8182288d4..2ff359fb2 100644 --- a/qemu/roms/seabios/src/block.h +++ b/qemu/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/qemu/roms/seabios/src/bmp.c b/qemu/roms/seabios/src/bmp.c index d8e76b789..96a2b3f22 100644 --- a/qemu/roms/seabios/src/bmp.c +++ b/qemu/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/qemu/roms/seabios/src/boot.c b/qemu/roms/seabios/src/boot.c index f23e9e154..e0f73a385 100644 --- a/qemu/roms/seabios/src/boot.c +++ b/qemu/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/qemu/roms/seabios/src/cdrom.c b/qemu/roms/seabios/src/cdrom.c index 92f34f42b..a4f31adde 100644 --- a/qemu/roms/seabios/src/cdrom.c +++ b/qemu/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/qemu/roms/seabios/src/clock.c b/qemu/roms/seabios/src/clock.c index 9ab0ac026..e83e0f338 100644 --- a/qemu/roms/seabios/src/clock.c +++ b/qemu/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/qemu/roms/seabios/src/config.h b/qemu/roms/seabios/src/config.h index 6da067d0b..6c47f161c 100644 --- a/qemu/roms/seabios/src/config.h +++ b/qemu/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/qemu/roms/seabios/src/disk.c b/qemu/roms/seabios/src/disk.c index 0e0af24b3..3854d0024 100644 --- a/qemu/roms/seabios/src/disk.c +++ b/qemu/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/qemu/roms/seabios/src/memmap.c b/qemu/roms/seabios/src/e820map.c index e03f8d0bf..39445cf63 100644 --- a/qemu/roms/seabios/src/memmap.c +++ b/qemu/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/qemu/roms/seabios/src/e820map.h b/qemu/roms/seabios/src/e820map.h new file mode 100644 index 000000000..de8b52300 --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/fw/biostables.c b/qemu/roms/seabios/src/fw/biostables.c index 50a891be8..9fb9ff9df 100644 --- a/qemu/roms/seabios/src/fw/biostables.c +++ b/qemu/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/qemu/roms/seabios/src/fw/coreboot.c b/qemu/roms/seabios/src/fw/coreboot.c index 8fd84493b..4fe12928c 100644 --- a/qemu/roms/seabios/src/fw/coreboot.c +++ b/qemu/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/qemu/roms/seabios/src/fw/csm.c b/qemu/roms/seabios/src/fw/csm.c index 7cdb398f2..7cadd12e5 100644 --- a/qemu/roms/seabios/src/fw/csm.c +++ b/qemu/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/qemu/roms/seabios/src/fw/dev-q35.h b/qemu/roms/seabios/src/fw/dev-q35.h index c6f8bd9e7..201825deb 100644 --- a/qemu/roms/seabios/src/fw/dev-q35.h +++ b/qemu/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/qemu/roms/seabios/src/fw/multiboot.c b/qemu/roms/seabios/src/fw/multiboot.c new file mode 100644 index 000000000..d9df06764 --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/fw/paravirt.c b/qemu/roms/seabios/src/fw/paravirt.c index db22ae8fc..3fae13a83 100644 --- a/qemu/roms/seabios/src/fw/paravirt.c +++ b/qemu/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/qemu/roms/seabios/src/fw/paravirt.h b/qemu/roms/seabios/src/fw/paravirt.h index 95ffb92ad..ed8e5f1f8 100644 --- a/qemu/roms/seabios/src/fw/paravirt.h +++ b/qemu/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/qemu/roms/seabios/src/fw/pciinit.c b/qemu/roms/seabios/src/fw/pciinit.c index 46ae7090e..c31c2fa0c 100644 --- a/qemu/roms/seabios/src/fw/pciinit.c +++ b/qemu/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/qemu/roms/seabios/src/fw/shadow.c b/qemu/roms/seabios/src/fw/shadow.c index 4f00006bf..ee87d36e0 100644 --- a/qemu/roms/seabios/src/fw/shadow.c +++ b/qemu/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/qemu/roms/seabios/src/fw/smbios.c b/qemu/roms/seabios/src/fw/smbios.c index dba054133..f3b5ad9dd 100644 --- a/qemu/roms/seabios/src/fw/smbios.c +++ b/qemu/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/qemu/roms/seabios/src/fw/smm.c b/qemu/roms/seabios/src/fw/smm.c index 6cb484e7e..8f042ee4d 100644 --- a/qemu/roms/seabios/src/fw/smm.c +++ b/qemu/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/qemu/roms/seabios/src/fw/smp.c b/qemu/roms/seabios/src/fw/smp.c index a466ea6e9..579acdbd0 100644 --- a/qemu/roms/seabios/src/fw/smp.c +++ b/qemu/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/qemu/roms/seabios/src/fw/xen.c b/qemu/roms/seabios/src/fw/xen.c index dd8e8afd4..3f19ef2dc 100644 --- a/qemu/roms/seabios/src/fw/xen.c +++ b/qemu/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/qemu/roms/seabios/src/hw/ahci.c b/qemu/roms/seabios/src/hw/ahci.c index 3193d81a6..83b747cb2 100644 --- a/qemu/roms/seabios/src/hw/ahci.c +++ b/qemu/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/qemu/roms/seabios/src/hw/ahci.h b/qemu/roms/seabios/src/hw/ahci.h index c8c755a3f..fa11d6619 100644 --- a/qemu/roms/seabios/src/hw/ahci.h +++ b/qemu/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/qemu/roms/seabios/src/hw/ata.c b/qemu/roms/seabios/src/hw/ata.c index d805706dd..fbbbbc1bb 100644 --- a/qemu/roms/seabios/src/hw/ata.c +++ b/qemu/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/qemu/roms/seabios/src/hw/ata.h b/qemu/roms/seabios/src/hw/ata.h index c73892bbe..cd14e59e9 100644 --- a/qemu/roms/seabios/src/hw/ata.h +++ b/qemu/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/qemu/roms/seabios/src/hw/blockcmd.c b/qemu/roms/seabios/src/hw/blockcmd.c index 78c0e65f4..0725b46db 100644 --- a/qemu/roms/seabios/src/hw/blockcmd.c +++ b/qemu/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/qemu/roms/seabios/src/hw/blockcmd.h b/qemu/roms/seabios/src/hw/blockcmd.h index df12a6d42..b543f85eb 100644 --- a/qemu/roms/seabios/src/hw/blockcmd.h +++ b/qemu/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/qemu/roms/seabios/src/hw/esp-scsi.c b/qemu/roms/seabios/src/hw/esp-scsi.c index 33cc44986..d4e47e3c5 100644 --- a/qemu/roms/seabios/src/hw/esp-scsi.c +++ b/qemu/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/qemu/roms/seabios/src/hw/esp-scsi.h b/qemu/roms/seabios/src/hw/esp-scsi.h index dc555f395..0616d14b1 100644 --- a/qemu/roms/seabios/src/hw/esp-scsi.h +++ b/qemu/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/qemu/roms/seabios/src/hw/floppy.c b/qemu/roms/seabios/src/hw/floppy.c index d60362a34..a14f7e093 100644 --- a/qemu/roms/seabios/src/hw/floppy.c +++ b/qemu/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/qemu/roms/seabios/src/hw/lsi-scsi.c b/qemu/roms/seabios/src/hw/lsi-scsi.c index b1d6bbf4b..ad3352886 100644 --- a/qemu/roms/seabios/src/hw/lsi-scsi.c +++ b/qemu/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/qemu/roms/seabios/src/hw/lsi-scsi.h b/qemu/roms/seabios/src/hw/lsi-scsi.h index 9c5a9b212..6baf4a162 100644 --- a/qemu/roms/seabios/src/hw/lsi-scsi.h +++ b/qemu/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/qemu/roms/seabios/src/hw/megasas.c b/qemu/roms/seabios/src/hw/megasas.c index b2a65e48b..cb1a2a653 100644 --- a/qemu/roms/seabios/src/hw/megasas.c +++ b/qemu/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/qemu/roms/seabios/src/hw/megasas.h b/qemu/roms/seabios/src/hw/megasas.h index 124042e1c..ed0e4f096 100644 --- a/qemu/roms/seabios/src/hw/megasas.h +++ b/qemu/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/qemu/roms/seabios/src/hw/pci.c b/qemu/roms/seabios/src/hw/pci.c index 0379b558e..a241d0675 100644 --- a/qemu/roms/seabios/src/hw/pci.c +++ b/qemu/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/qemu/roms/seabios/src/hw/pci.h b/qemu/roms/seabios/src/hw/pci.h index 0aaa84c1a..fc5e7b9bf 100644 --- a/qemu/roms/seabios/src/hw/pci.h +++ b/qemu/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/qemu/roms/seabios/src/hw/pci_ids.h b/qemu/roms/seabios/src/hw/pci_ids.h index 1cd4f7269..cdf9b3cbc 100644 --- a/qemu/roms/seabios/src/hw/pci_ids.h +++ b/qemu/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/qemu/roms/seabios/src/hw/pic.c b/qemu/roms/seabios/src/hw/pic.c index 6ff696765..d8b9764c7 100644 --- a/qemu/roms/seabios/src/hw/pic.c +++ b/qemu/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/qemu/roms/seabios/src/hw/pic.h b/qemu/roms/seabios/src/hw/pic.h index 6947b6e81..f2d9f6130 100644 --- a/qemu/roms/seabios/src/hw/pic.h +++ b/qemu/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/qemu/roms/seabios/src/hw/ps2port.c b/qemu/roms/seabios/src/hw/ps2port.c index 04995c881..d5504f71e 100644 --- a/qemu/roms/seabios/src/hw/ps2port.c +++ b/qemu/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/qemu/roms/seabios/src/hw/ps2port.h b/qemu/roms/seabios/src/hw/ps2port.h index e5d9014b7..1338406ac 100644 --- a/qemu/roms/seabios/src/hw/ps2port.h +++ b/qemu/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/qemu/roms/seabios/src/hw/pvscsi.c b/qemu/roms/seabios/src/hw/pvscsi.c index 601a551db..fa20efef7 100644 --- a/qemu/roms/seabios/src/hw/pvscsi.c +++ b/qemu/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/qemu/roms/seabios/src/hw/pvscsi.h b/qemu/roms/seabios/src/hw/pvscsi.h index fde9f0b98..5af7dcb0e 100644 --- a/qemu/roms/seabios/src/hw/pvscsi.h +++ b/qemu/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/qemu/roms/seabios/src/hw/ramdisk.c b/qemu/roms/seabios/src/hw/ramdisk.c index 1177bc00a..adec1d1b3 100644 --- a/qemu/roms/seabios/src/hw/ramdisk.c +++ b/qemu/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/qemu/roms/seabios/src/hw/rtc.c b/qemu/roms/seabios/src/hw/rtc.c index 628d5429f..9649a5a79 100644 --- a/qemu/roms/seabios/src/hw/rtc.c +++ b/qemu/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/qemu/roms/seabios/src/hw/sdcard.c b/qemu/roms/seabios/src/hw/sdcard.c index 6ff93c856..e01e1bb02 100644 --- a/qemu/roms/seabios/src/hw/sdcard.c +++ b/qemu/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/qemu/roms/seabios/src/hw/timer.c b/qemu/roms/seabios/src/hw/timer.c index 5edc9fdbb..03d22b2f5 100644 --- a/qemu/roms/seabios/src/hw/timer.c +++ b/qemu/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/qemu/roms/seabios/src/hw/tpm_drivers.c b/qemu/roms/seabios/src/hw/tpm_drivers.c new file mode 100644 index 000000000..444eac39b --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/hw/tpm_drivers.h b/qemu/roms/seabios/src/hw/tpm_drivers.h new file mode 100644 index 000000000..34bb12d1c --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/hw/usb-hid.h b/qemu/roms/seabios/src/hw/usb-hid.h index ef34e7963..fd7b8f8be 100644 --- a/qemu/roms/seabios/src/hw/usb-hid.h +++ b/qemu/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/qemu/roms/seabios/src/hw/usb-msc.c b/qemu/roms/seabios/src/hw/usb-msc.c index d90319f51..a234f13be 100644 --- a/qemu/roms/seabios/src/hw/usb-msc.c +++ b/qemu/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/qemu/roms/seabios/src/hw/usb-msc.h b/qemu/roms/seabios/src/hw/usb-msc.h index c40d75556..ff3c38038 100644 --- a/qemu/roms/seabios/src/hw/usb-msc.h +++ b/qemu/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/qemu/roms/seabios/src/hw/usb-uas.c b/qemu/roms/seabios/src/hw/usb-uas.c index 6ef8d0912..10e38454a 100644 --- a/qemu/roms/seabios/src/hw/usb-uas.c +++ b/qemu/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/qemu/roms/seabios/src/hw/usb-uas.h b/qemu/roms/seabios/src/hw/usb-uas.h index ad91c5f60..8b2f810e9 100644 --- a/qemu/roms/seabios/src/hw/usb-uas.h +++ b/qemu/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/qemu/roms/seabios/src/hw/usb-xhci.c b/qemu/roms/seabios/src/hw/usb-xhci.c index fd58334dc..654febaad 100644 --- a/qemu/roms/seabios/src/hw/usb-xhci.c +++ b/qemu/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/qemu/roms/seabios/src/hw/usb.c b/qemu/roms/seabios/src/hw/usb.c index 1b4ea8bed..e46092c63 100644 --- a/qemu/roms/seabios/src/hw/usb.c +++ b/qemu/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/qemu/roms/seabios/src/hw/virtio-blk.c b/qemu/roms/seabios/src/hw/virtio-blk.c index e2dbd3c94..20a79ebba 100644 --- a/qemu/roms/seabios/src/hw/virtio-blk.c +++ b/qemu/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/qemu/roms/seabios/src/hw/virtio-blk.h b/qemu/roms/seabios/src/hw/virtio-blk.h index b233c744b..157bed627 100644 --- a/qemu/roms/seabios/src/hw/virtio-blk.h +++ b/qemu/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/qemu/roms/seabios/src/hw/virtio-pci.c b/qemu/roms/seabios/src/hw/virtio-pci.c index b9b3ab1e3..6df519489 100644 --- a/qemu/roms/seabios/src/hw/virtio-pci.c +++ b/qemu/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/qemu/roms/seabios/src/hw/virtio-pci.h b/qemu/roms/seabios/src/hw/virtio-pci.h index bc04b039e..b11c3555e 100644 --- a/qemu/roms/seabios/src/hw/virtio-pci.h +++ b/qemu/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/qemu/roms/seabios/src/hw/virtio-ring.c b/qemu/roms/seabios/src/hw/virtio-ring.c index 97e0b3487..7205a0acd 100644 --- a/qemu/roms/seabios/src/hw/virtio-ring.c +++ b/qemu/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/qemu/roms/seabios/src/hw/virtio-ring.h b/qemu/roms/seabios/src/hw/virtio-ring.h index b7a7aafb2..7665fd54b 100644 --- a/qemu/roms/seabios/src/hw/virtio-ring.h +++ b/qemu/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/qemu/roms/seabios/src/hw/virtio-scsi.c b/qemu/roms/seabios/src/hw/virtio-scsi.c index 8f966875b..80afd04ca 100644 --- a/qemu/roms/seabios/src/hw/virtio-scsi.c +++ b/qemu/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/qemu/roms/seabios/src/hw/virtio-scsi.h b/qemu/roms/seabios/src/hw/virtio-scsi.h index 96c3701d2..7532cc98e 100644 --- a/qemu/roms/seabios/src/hw/virtio-scsi.h +++ b/qemu/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/qemu/roms/seabios/src/list.h b/qemu/roms/seabios/src/list.h index de656b9d6..94512e306 100644 --- a/qemu/roms/seabios/src/list.h +++ b/qemu/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/qemu/roms/seabios/src/malloc.c b/qemu/roms/seabios/src/malloc.c index c4cb17149..3733855ca 100644 --- a/qemu/roms/seabios/src/malloc.c +++ b/qemu/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/qemu/roms/seabios/src/malloc.h b/qemu/roms/seabios/src/malloc.h index 2bcb5bf6d..960a7f800 100644 --- a/qemu/roms/seabios/src/malloc.h +++ b/qemu/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/qemu/roms/seabios/src/memmap.h b/qemu/roms/seabios/src/memmap.h index 7bda56e2b..22bd4bcb8 100644 --- a/qemu/roms/seabios/src/memmap.h +++ b/qemu/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/qemu/roms/seabios/src/misc.c b/qemu/roms/seabios/src/misc.c index 8caaf31d8..f02237c36 100644 --- a/qemu/roms/seabios/src/misc.c +++ b/qemu/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/qemu/roms/seabios/src/mouse.c b/qemu/roms/seabios/src/mouse.c index 6d1f5b77e..b7ad7c62a 100644 --- a/qemu/roms/seabios/src/mouse.c +++ b/qemu/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/qemu/roms/seabios/src/optionroms.c b/qemu/roms/seabios/src/optionroms.c index 93d9d2fe6..c81eff2d2 100644 --- a/qemu/roms/seabios/src/optionroms.c +++ b/qemu/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/qemu/roms/seabios/src/output.c b/qemu/roms/seabios/src/output.c index 45397b3f6..8a883889c 100644 --- a/qemu/roms/seabios/src/output.c +++ b/qemu/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/qemu/roms/seabios/src/pmm.c b/qemu/roms/seabios/src/pmm.c index 304faab2c..640341472 100644 --- a/qemu/roms/seabios/src/pmm.c +++ b/qemu/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/qemu/roms/seabios/src/post.c b/qemu/roms/seabios/src/post.c index 9ea5620c9..49c22b875 100644 --- a/qemu/roms/seabios/src/post.c +++ b/qemu/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/qemu/roms/seabios/src/resume.c b/qemu/roms/seabios/src/resume.c index 19031747c..a5465d877 100644 --- a/qemu/roms/seabios/src/resume.c +++ b/qemu/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/qemu/roms/seabios/src/romlayout.S b/qemu/roms/seabios/src/romlayout.S index 93b6874e7..53cc0f5e3 100644 --- a/qemu/roms/seabios/src/romlayout.S +++ b/qemu/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/qemu/roms/seabios/src/sha1.c b/qemu/roms/seabios/src/sha1.c new file mode 100644 index 000000000..2ecb3cb89 --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/sha1.h b/qemu/roms/seabios/src/sha1.h new file mode 100644 index 000000000..07aabf34f --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/stacks.c b/qemu/roms/seabios/src/stacks.c index 1dbdfe9bb..ef6a70775 100644 --- a/qemu/roms/seabios/src/stacks.c +++ b/qemu/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/qemu/roms/seabios/src/stacks.h b/qemu/roms/seabios/src/stacks.h index 82c4c3c85..c71bdc8e3 100644 --- a/qemu/roms/seabios/src/stacks.h +++ b/qemu/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/qemu/roms/seabios/src/std/acpi.h b/qemu/roms/seabios/src/std/acpi.h index e0d9516ba..b672bbee4 100644 --- a/qemu/roms/seabios/src/std/acpi.h +++ b/qemu/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/qemu/roms/seabios/src/std/bda.h b/qemu/roms/seabios/src/std/bda.h index c321266e2..4ad6605d4 100644 --- a/qemu/roms/seabios/src/std/bda.h +++ b/qemu/roms/seabios/src/std/bda.h @@ -7,7 +7,7 @@ /**************************************************************** - * Interupt vector table + * Interrupt vector table ****************************************************************/ struct rmode_IVT { diff --git a/qemu/roms/seabios/src/std/multiboot.h b/qemu/roms/seabios/src/std/multiboot.h new file mode 100644 index 000000000..6c9512703 --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/std/smbios.h b/qemu/roms/seabios/src/std/smbios.h index 05137167a..4ccf2ea34 100644 --- a/qemu/roms/seabios/src/std/smbios.h +++ b/qemu/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/qemu/roms/seabios/src/string.c b/qemu/roms/seabios/src/string.c index 2e4e43746..adb8198f8 100644 --- a/qemu/roms/seabios/src/string.c +++ b/qemu/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/qemu/roms/seabios/src/string.h b/qemu/roms/seabios/src/string.h index a557d6a44..d069989db 100644 --- a/qemu/roms/seabios/src/string.h +++ b/qemu/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/qemu/roms/seabios/src/system.c b/qemu/roms/seabios/src/system.c index 60a6fce58..438e60e2c 100644 --- a/qemu/roms/seabios/src/system.c +++ b/qemu/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/qemu/roms/seabios/src/tcgbios.c b/qemu/roms/seabios/src/tcgbios.c new file mode 100644 index 000000000..09954825c --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/tcgbios.h b/qemu/roms/seabios/src/tcgbios.h new file mode 100644 index 000000000..4b7eaabef --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/types.h b/qemu/roms/seabios/src/types.h index 097372cdb..19d9f6c14 100644 --- a/qemu/roms/seabios/src/types.h +++ b/qemu/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/qemu/roms/seabios/src/util.h b/qemu/roms/seabios/src/util.h index 09bb8a9f3..cba3359d5 100644 --- a/qemu/roms/seabios/src/util.h +++ b/qemu/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/qemu/roms/seabios/src/version.c b/qemu/roms/seabios/src/version.c new file mode 100644 index 000000000..a8a58cf09 --- /dev/null +++ b/qemu/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/qemu/roms/seabios/src/vgahooks.c b/qemu/roms/seabios/src/vgahooks.c index 6a4acfeaf..48efb086c 100644 --- a/qemu/roms/seabios/src/vgahooks.c +++ b/qemu/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/qemu/roms/seabios/src/x86.h b/qemu/roms/seabios/src/x86.h index 7798b1c17..53378e9ed 100644 --- a/qemu/roms/seabios/src/x86.h +++ b/qemu/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/qemu/roms/seabios/vgasrc/Kconfig b/qemu/roms/seabios/vgasrc/Kconfig index 91d590ae2..f5098a4bd 100644 --- a/qemu/roms/seabios/vgasrc/Kconfig +++ b/qemu/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/qemu/roms/seabios/vgasrc/geodevga.h b/qemu/roms/seabios/vgasrc/geodevga.h index 61d78084d..c99f54bb1 100644 --- a/qemu/roms/seabios/vgasrc/geodevga.h +++ b/qemu/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/qemu/roms/seabios/vgasrc/vgabios.c b/qemu/roms/seabios/vgasrc/vgabios.c index 4aa50e1c1..f07e85bd3 100644 --- a/qemu/roms/seabios/vgasrc/vgabios.c +++ b/qemu/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/qemu/roms/seabios/vgasrc/vgabios.h b/qemu/roms/seabios/vgasrc/vgabios.h index fd796f2e6..831f69407 100644 --- a/qemu/roms/seabios/vgasrc/vgabios.h +++ b/qemu/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/qemu/roms/seabios/vgasrc/vgaentry.S b/qemu/roms/seabios/vgasrc/vgaentry.S index d9ebdb93c..53be2b38c 100644 --- a/qemu/roms/seabios/vgasrc/vgaentry.S +++ b/qemu/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/qemu/roms/seabios/vgasrc/vgafb.c b/qemu/roms/seabios/vgasrc/vgafb.c index 1a94fcf70..5d1ecc936 100644 --- a/qemu/roms/seabios/vgasrc/vgafb.c +++ b/qemu/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/qemu/roms/seabios/vgasrc/vgainit.c b/qemu/roms/seabios/vgasrc/vgainit.c index 8d1226182..40997dbbd 100644 --- a/qemu/roms/seabios/vgasrc/vgainit.c +++ b/qemu/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/qemu/roms/seabios/vgasrc/vgaversion.c b/qemu/roms/seabios/vgasrc/vgaversion.c new file mode 100644 index 000000000..1ef5ddb79 --- /dev/null +++ b/qemu/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; |