Changeset 37268 in vbox
- Timestamp:
- May 30, 2011 9:14:14 PM (14 years ago)
- Location:
- trunk/src/VBox/Devices/PC/BIOS
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/BIOS/ahci.c
r36877 r37268 15 15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 16 16 */ 17 18 #define AHCI_MAX_STORAGE_DEVICES 4 19 20 typedef struct 21 { 22 Bit8u type; // Detected type of ata (ata/atapi/none/unknown/scsi) 23 Bit8u device; // Detected type of attached devices (hd/cd/none) 24 #if 0 25 Bit8u removable; // Removable device flag 26 Bit8u lock; // Locks for removable devices 27 #endif 28 Bit16u blksize; // block size 29 30 Bit8u translation; // type of translation 31 chs_t lchs; // Logical CHS 32 chs_t pchs; // Physical CHS 33 34 Bit32u sectors; // Total sectors count 35 Bit8u port; // Port this device is on. 36 } ahci_device_t; 37 38 /** 39 * AHCI controller data. 40 */ 41 typedef struct 42 { 43 /** The AHCI command list as defined by chapter 4.2.2 of the Intel AHCI spec. 44 * Because the BIOS doesn't support NCQ only the first command header is defined 45 * to save memory. - Must be aligned on a 1K boundary. 46 */ 47 Bit32u abCmdHdr[0x8]; 48 /** Align the next structure on a 128 byte boundary. */ 49 Bit8u abAlignment1[0x60]; 50 /** The command table of one request as defined by chapter 4.2.3 of the Intel AHCI spec. 51 * Must be aligned on 128 byte boundary. 52 */ 53 Bit8u abCmd[0x90]; 54 /** Alignment */ 55 Bit8u abAlignment2[0xF0]; 56 /** Memory for the received command FIS area as specified by chapter 4.2.1 57 * of the Intel AHCI spec. This area is normally 256 bytes big but to save memory 58 * only the first 96 bytes are used because it is assumed that the controller 59 * never writes to the UFIS or reserved area. - Must be aligned on a 256byte boundary. 60 */ 61 Bit8u abFisRecv[0x60]; 62 /** Base I/O port for the index/data register pair. */ 63 Bit16u iobase; 64 /** Current port which uses the memory to communicate with the controller. */ 65 Bit8u port; 66 /** AHCI device information. */ 67 ahci_device_t aDevices[AHCI_MAX_STORAGE_DEVICES]; 68 /** Map between (bios hd id - 0x80) and ahci devices. */ 69 Bit8u cHardDisks; 70 Bit8u aHdIdMap[AHCI_MAX_STORAGE_DEVICES]; 71 /** Map between (bios cd id - 0xE0) and ahci_devices. */ 72 Bit8u cCdDrives; 73 Bit8u aCdIdMap[AHCI_MAX_STORAGE_DEVICES]; 74 } ahci_t; 75 76 #define AhciData ((ahci_t *) 0) 17 77 18 78 /** Supported methods of the PCI BIOS. */ … … 76 136 #define AHCI_REG_PORT_FBU 0x0c 77 137 #define AHCI_REG_PORT_IS 0x10 138 # define AHCI_REG_PORT_IS_DHRS RT_BIT_32(0) 78 139 #define AHCI_REG_PORT_IE 0x14 79 140 #define AHCI_REG_PORT_CMD 0x18 … … 108 169 /** Writes to the given port register. */ 109 170 #define VBOXAHCI_PORT_WRITE_REG(iobase, port, reg, val) \ 110 VBOX _AHCI_WRITE_REG((iobase), VBOXAHCI_PORT_REG((port), (reg)), val)171 VBOXAHCI_WRITE_REG((iobase), VBOXAHCI_PORT_REG((port), (reg)), val) 111 172 112 173 /** Reads from the given port register. */ 113 174 #define VBOXAHCI_PORT_READ_REG(iobase, port, reg, val) \ 114 VBOX_AHCI_READ_REG((iobase), VBOXAHCI_PORT_REG((port), (reg)), val) 175 VBOXAHCI_READ_REG((iobase), VBOXAHCI_PORT_REG((port), (reg)), val) 176 177 #define ATA_CMD_IDENTIFY_DEVICE 0xEC 115 178 116 179 /** … … 498 561 } 499 562 500 static int ahci_port_init(u16IoBase, u8Port) 563 /** 564 * Converts a segment:offset pair into a 32bit physical address. 565 */ 566 static Bit32u ahci_addr_to_phys(u16Segment, u16Offset) 567 Bit16u u16Segment, u16Offset; 568 { 569 ASM_START 570 push bp 571 mov bp, sp 572 573 push bx 574 push eax 575 576 xor eax, eax 577 xor ebx, ebx 578 mov ax, _ahci_addr_to_phys.u16Segment + 2[bp] 579 shl eax, #4 580 add bx, _ahci_addr_to_phys.u16Offset + 2[bp] 581 add eax, ebx 582 583 mov bx, ax 584 shr eax, #16 585 mov dx, ax 586 587 pop eax 588 mov ax, bx 589 pop bx 590 591 pop bp 592 ASM_END 593 } 594 595 /** 596 * Issues a command to the SATA controller and waits for completion. 597 */ 598 static void ahci_port_cmd_sync(SegAhci, u16IoBase, fWrite, fAtapi, cFisDWords, cbData) 599 Bit16u SegAhci; 600 Bit16u u16IoBase; 601 bx_bool fWrite; 602 bx_bool fAtapi; 603 Bit8u cFisDWords; 604 Bit16u cbData; 605 { 606 Bit8u u8Port; 607 608 u8Port = read_byte(SegAhci, &AhciData->port); 609 610 if (u8Port != 0xff) 611 { 612 Bit32u u32Val; 613 614 /* Prepare the command header. */ 615 u32Val = (1L << 16) | RT_BIT_32(7); 616 if (fWrite) 617 u32Val |= RT_BIT_32(6); 618 619 if (fAtapi) 620 u32Val |= RT_BIT_32(5); 621 622 u32Val |= cFisDWords; 623 624 write_dword(SegAhci, &AhciData->abCmdHdr[0], u32Val); 625 write_dword(SegAhci, &AhciData->abCmdHdr[1], (Bit32u)cbData); 626 write_dword(SegAhci, &AhciData->abCmdHdr[2], 627 ahci_addr_to_phys(SegAhci, &AhciData->abCmd[0])); 628 629 /* Enable Command engine. */ 630 ahci_ctrl_set_bits(u16IoBase, VBOXAHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD), 631 AHCI_REG_PORT_CMD_ST); 632 633 /* Queue command. */ 634 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CI, 0x1L); 635 636 /* Wait for a D2H Fis. */ 637 while (ahci_ctrl_is_bit_set(u16IoBase, VBOXAHCI_PORT_REG(u8Port, AHCI_REG_PORT_IS), 638 AHCI_REG_PORT_IS_DHRS) == 0) 639 { 640 VBOXAHCI_DEBUG("AHCI: Waiting for a D2H Fis\n"); 641 } 642 643 ahci_ctrl_set_bits(u16IoBase, VBOXAHCI_PORT_REG(u8Port, AHCI_REG_PORT_IS), 644 AHCI_REG_PORT_IS_DHRS); /* Acknowledge received D2H FIS. */ 645 646 /* Disable command engine. */ 647 ahci_ctrl_clear_bits(u16IoBase, VBOXAHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD), 648 AHCI_REG_PORT_CMD_ST); 649 650 /** @todo: Examine status. */ 651 } 652 else 653 VBOXAHCI_DEBUG("AHCI: Invalid port given\n"); 654 } 655 656 /** 657 * Issue command to device. 658 */ 659 static void ahci_cmd_data(SegAhci, u16IoBase, u8Cmd, u8Feat, u8Device, u8CylHigh, u8CylLow, u8Sect, 660 u8FeatExp, u8CylHighExp, u8CylLowExp, u8SectExp, u8SectCount, u8SectCountExp, 661 SegData, OffData, cbData, fWrite) 662 Bit16u SegAhci; 663 Bit16u u16IoBase; 664 Bit8u u8Cmd, u8Feat, u8Device, u8CylHigh, u8CylLow, u8Sect, u8FeatExp, 665 u8CylHighExp, u8CylLowExp, u8SectExp, u8SectCount, u8SectCountExp; 666 Bit16u SegData, OffData, cbData; 667 bx_bool fWrite; 668 { 669 memsetb(SegAhci, &AhciData->abCmd[0], 0, sizeof(AhciData->abCmd)); 670 671 /* Prepare the FIS. */ 672 write_byte(SegAhci, &AhciData->abCmd[0], 0x27); /* FIS type H2D. */ 673 write_byte(SegAhci, &AhciData->abCmd[1], 1 << 7); /* Command update. */ 674 write_byte(SegAhci, &AhciData->abCmd[2], u8Cmd); 675 write_byte(SegAhci, &AhciData->abCmd[3], u8Feat); 676 677 write_byte(SegAhci, &AhciData->abCmd[4], u8Sect); 678 write_byte(SegAhci, &AhciData->abCmd[5], u8CylLow); 679 write_byte(SegAhci, &AhciData->abCmd[6], u8CylHigh); 680 write_byte(SegAhci, &AhciData->abCmd[7], u8Device); 681 682 write_byte(SegAhci, &AhciData->abCmd[8], u8SectExp); 683 write_byte(SegAhci, &AhciData->abCmd[9], u8CylLowExp); 684 write_byte(SegAhci, &AhciData->abCmd[10], u8CylHighExp); 685 write_byte(SegAhci, &AhciData->abCmd[11], u8FeatExp); 686 687 write_byte(SegAhci, &AhciData->abCmd[12], u8SectCount); 688 write_byte(SegAhci, &AhciData->abCmd[13], u8SectCountExp); 689 690 /* Prepare PRDT. */ 691 write_dword(SegAhci, &AhciData->abCmd[0x80], ahci_addr_to_phys(SegData, OffData)); 692 write_dword(SegAhci, &AhciData->abCmd[0x8c], (Bit32u)cbData); 693 694 ahci_port_cmd_sync(SegAhci, u16IoBase, fWrite, 0, 5, cbData); 695 } 696 697 /** 698 * Deinits the curent active port. 699 */ 700 static void ahci_port_deinit_current(SegAhci, u16IoBase) 701 Bit16u SegAhci; 702 Bit16u u16IoBase; 703 { 704 Bit8u u8Port; 705 706 u8Port = read_byte(SegAhci, &AhciData->port); 707 708 if (u8Port != 0xff) 709 { 710 /* Put the port into an idle state. */ 711 ahci_ctrl_clear_bits(u16IoBase, VBOXAHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD), 712 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST); 713 714 while (ahci_ctrl_is_bit_set(u16IoBase, VBOXAHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD), 715 AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_ST | AHCI_REG_PORT_CMD_FRE | AHCI_REG_PORT_CMD_CR) == 1) 716 { 717 VBOXAHCI_DEBUG("AHCI: Waiting for the port to idle\n"); 718 } 719 720 /* 721 * Port idles, set up memory for commands and received FIS and program the 722 * address registers. 723 */ 724 memsetb(SegAhci, &AhciData->abFisRecv[0], 0, 0x60); 725 memsetb(SegAhci, &AhciData->abCmdHdr[0], 0, 0x20); 726 memsetb(SegAhci, &AhciData->abCmd[0], 0, 0x84); 727 728 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_FB, 0L); 729 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_FBU, 0L); 730 731 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CLB, 0L); 732 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CLBU, 0L); 733 734 /* Disable all interrupts. */ 735 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_IE, 0L); 736 737 write_byte(SegAhci, &AhciData->port, 0xff); 738 } 739 } 740 741 /** 742 * Brings a port into a minimal state to make device detection possible 743 * or to queue requests. 744 */ 745 static void ahci_port_init(SegAhci, u16IoBase, u8Port) 746 Bit16u SegAhci; 501 747 Bit16u u16IoBase; 502 748 Bit8u u8Port; 503 749 { 750 Bit32u u32PhysAddr; 751 752 /* Deinit any other port first. */ 753 ahci_port_deinit_current(SegAhci, u16IoBase); 504 754 505 755 /* Put the port into an idle state. */ … … 517 767 * address registers. 518 768 */ 519 520 return -1; 769 memsetb(SegAhci, &AhciData->abFisRecv[0], 0, 0x60); 770 memsetb(SegAhci, &AhciData->abCmdHdr[0], 0, 0x20); 771 memsetb(SegAhci, &AhciData->abCmd[0], 0, 0x84); 772 773 u32PhysAddr = ahci_addr_to_phys(SegAhci, &AhciData->abFisRecv); 774 VBOXAHCI_DEBUG("AHCI: FIS receive area %lx from %x:%x\n", u32PhysAddr, SegAhci, &AhciData->abFisRecv); 775 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_FB, u32PhysAddr); 776 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_FBU, 0L); 777 778 u32PhysAddr = ahci_addr_to_phys(SegAhci, &AhciData->abCmdHdr); 779 VBOXAHCI_DEBUG("AHCI: CMD list area %lx\n", u32PhysAddr); 780 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CLB, u32PhysAddr); 781 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_CLBU, 0L); 782 783 /* Disable all interrupts. */ 784 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_IE, 0L); 785 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_IS, 0xffffffffL); 786 /* Clear all errors. */ 787 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_SERR, 0xffffffffL); 788 789 write_byte(SegAhci, &AhciData->port, u8Port); 790 } 791 792 static void ahci_port_detect_device(SegAhci, u16IoBase, u8Port) 793 Bit16u SegAhci; 794 Bit16u u16IoBase; 795 Bit8u u8Port; 796 { 797 Bit32u val; 798 799 ahci_port_init(SegAhci, u16IoBase, u8Port); 800 801 /* Reset connection. */ 802 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_SCTL, 0x01L); 803 /* 804 * According to the spec we should wait at least 1msec until the reset 805 * is cleared but this is a virtual controller so we don't have to. 806 */ 807 VBOXAHCI_PORT_WRITE_REG(u16IoBase, u8Port, AHCI_REG_PORT_SCTL, 0x00L); 808 809 /* Check if there is a device on the port. */ 810 VBOXAHCI_PORT_READ_REG(u16IoBase, u8Port, AHCI_REG_PORT_SSTS, val); 811 if (ahci_ctrl_extract_bits(val, 0xfL, 0) == 0x3L) 812 { 813 VBOXAHCI_DEBUG("AHCI: Device detected on port %d\n", u8Port); 814 815 /* Device detected, enable FIS receive. */ 816 ahci_ctrl_set_bits(u16IoBase, VBOXAHCI_PORT_REG(u8Port, AHCI_REG_PORT_CMD), 817 AHCI_REG_PORT_CMD_FRE); 818 819 /* Check signature to determine device type. */ 820 VBOXAHCI_PORT_READ_REG(u16IoBase, u8Port, AHCI_REG_PORT_SIG, val); 821 if (val == 0x101L) 822 { 823 Bit8u idxHdCurr = read_byte(SegAhci, &AhciData->cHardDisks); 824 if (idxHdCurr < AHCI_MAX_STORAGE_DEVICES) 825 { 826 Bit32u cSectors; 827 Bit8u abBuffer[0x0200]; 828 829 VBOXAHCI_DEBUG("AHCI: Detected hard disk\n"); 830 831 /* Identify device. */ 832 ahci_cmd_data(SegAhci, u16IoBase, ATA_CMD_IDENTIFY_DEVICE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, get_SS(), abBuffer, sizeof(abBuffer), 0); 833 834 write_byte(SegAhci, &AhciData->aDevices[idxHdCurr].port, u8Port); 835 VBOXAHCI_DEBUG("AHCI: %lld sectors\n", cSectors); 836 837 838 idxHdCurr++; 839 write_byte(SegAhci, &AhciData->cHardDisks, idxHdCurr); 840 } 841 else 842 VBOXAHCI_DEBUG("AHCI: Reached maximum hard disk count, skipping\n"); 843 } 844 else if (val == 0xeb140101) 845 { 846 VBOXAHCI_DEBUG("AHCI: Detected ATAPI device\n"); 847 } 848 else 849 VBOXAHCI_DEBUG("AHCI: Unknown device ignoring\n"); 850 } 851 } 852 853 static Bit16u ahci_mem_alloc() 854 { 855 Bit16u cBaseMem1K; 856 Bit16u SegStart; 857 858 cBaseMem1K = read_byte(0x00, 0x0413); 859 860 VBOXAHCI_DEBUG("AHCI: %x K of base memory available\n", cBaseMem1K); 861 862 if (cBaseMem1K == 0) 863 return 0; 864 865 cBaseMem1K--; /* Allocate one block. */ 866 SegStart = (Bit16u)(((Bit32u)cBaseMem1K * 1024) >> 4); /* Calculate start segment. */ 867 868 write_byte(0x00, 0x0413, cBaseMem1K); 869 870 return SegStart; 521 871 } 522 872 … … 524 874 Bit16u u16IoBase; 525 875 { 526 int rc = 0;527 876 Bit8u i, cPorts; 528 877 Bit32u val; 878 Bit16u ebda_seg; 879 Bit16u SegAhci; 880 881 ebda_seg = read_word(0x0040, 0x000E); 529 882 530 883 VBOXAHCI_READ_REG(u16IoBase, AHCI_REG_VS, val); … … 532 885 ahci_ctrl_extract_bits(val, 0xffff0000, 16), 533 886 ahci_ctrl_extract_bits(val, 0x0000ffff, 0)); 887 888 /* Allocate 1K of base memory. */ 889 SegAhci = ahci_mem_alloc(); 890 if (SegAhci == 0) 891 { 892 VBOXAHCI_DEBUG("AHCI: Could not allocate 1K of memory, can't boot from controller\n"); 893 return 0; 894 } 895 896 write_word(ebda_seg, &EbdaData->SegAhci, SegAhci); 897 write_byte(SegAhci, &AhciData->port, 0xff); 534 898 535 899 /* Reset the controller. */ … … 552 916 { 553 917 VBOXAHCI_DEBUG("AHCI: Port %u is present\n", i); 554 rc = ahci_port_init(u16IoBase, i);918 ahci_port_detect_device(SegAhci, u16IoBase, i); 555 919 cPorts--; 556 920 if (cPorts == 0) … … 560 924 } 561 925 562 return rc;926 return 0; 563 927 } 564 928 -
trunk/src/VBox/Devices/PC/BIOS/rombios.c
r37049 r37268 778 778 #endif 779 779 780 #ifdef VBOX_WITH_BIOS_AHCI781 typedef struct {782 Bit16u iobase;783 } ahci_t;784 #endif785 786 780 // for access to EBDA area 787 781 // The EBDA structure should conform to … … 813 807 814 808 #ifdef VBOX_WITH_BIOS_AHCI 815 ahci_t ahci; 809 // AHCI driver data segment; 810 Bit16u SegAhci; 816 811 #endif 817 812 … … 1290 1285 mov bp, sp 1291 1286 1292 push dx1287 push bx 1293 1288 mov dx, 4[bp] 1294 1289 in eax, dx 1295 pop dx 1290 mov bx, ax ; Save lower 16 bits 1291 shr eax, #16 1292 mov dx, ax 1293 mov ax, bx 1294 pop bx 1296 1295 1297 1296 pop bp … … 2731 2730 } 2732 2731 2732 #ifdef VBOX 2733 // we don't want any noisy output for now 2734 #else /* !VBOX */ 2733 2735 { 2734 2736 Bit32u sizeinmb; … … 2764 2766 } 2765 2767 2766 #ifdef VBOX2767 // we don't want any noisy output for now2768 #else /* !VBOX */2769 2768 switch (type) { 2770 2769 case ATA_TYPE_ATA: … … 2785 2784 break; 2786 2785 } 2786 } 2787 2787 #endif /* !VBOX */ 2788 }2789 2788 } 2790 2789 … … 4851 4850 * use the 0xe0000-0xeffff area. It does use the 4852 4851 * 0xd0000-0xdffff area for the BIOS logo, but it's 4853 * not worth marking it as reserved. Note that various 4852 * not worth marking it as reserved. (this is not 4853 * true anymore because the VGA adapter handles the logo stuff) 4854 * The whole 0xe0000-0xfffff can be used for the BIOS. 4855 * Note that various 4854 4856 * Windows versions don't accept (read: in debug builds 4855 4857 * they trigger the "Too many similar traps" assertion)
Note:
See TracChangeset
for help on using the changeset viewer.