target-arm queue:

* hw/arm: Add GMAC devices to NPCM8XX SoC
  * hw/arm: Add missing psci_conduit to NPCM8XX SoC boot info
  * docs/interop: convert text files to restructuredText
  * target/arm: Some minor refactorings
  * tests/functional: Add a test for the Stellaris arm machines
  * hw/block: Drop unused nand.c
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmg5qPYZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3tXUD/9tKWMUEYl23gd9IB5Ee3xK
 dcgG4Fzv0Ae8HLTd1agyhrg5S2LiXmFi37IO65d8Wxf7Y2TBU+kj1m3aB/C3w9Bx
 VdHGfNsHAMuYdYCOEm9OvmuSMYSxDRd43pNWdBxbc9/MgLM24rImJ05YHoZFVGrY
 S5olcZOl3/ttFHtigO4AYAbxkHMAJ5gDyNJiuk88IPx9WGYdmmM4mzJ/m17/Re01
 hdOUi0DKQO7kl+646knSU0dicu8NeO5rBAyJzu3vFBnvYXznjd9XaxF+A0Opl54P
 aBUZz27nDLvnGQrN8B5CjevjUysko+KL/L4NRqebeQKhSe4C8tKFIDocRTGyOEoR
 SAI0UpZbcX/mXt52aksSwMNG8oRvHOqpJRnNaaCZQoMjK7SlFwi6WctDpwiGt/Hu
 WaVlXaC77YRiKf1RAgH2CxV04ts342v+bndjfi4vy8D4zbTvwgqKxg+qk3N+JBMR
 ZUI5Gz3OcGXbw5awJAYbJmyo6qxBysmdHpPY8I1eW0ohzRx1rZ3Vka4yIje5mgO+
 5yFpSy4GDRqNYKgGwlXRaseB38qKL4bEz0+uGzXYqdG7ACBz0xhT5H10npXkX/au
 LumtwW1sohsv3Xf9oBHQ1WQel7LDcWGVEZHZn6q67mazjvivLjREvA74dq1e8bqD
 zovTStIpBYRChXTRK1ShUQ==
 =Xts4
 -----END PGP SIGNATURE-----

Merge tag 'pull-target-arm-20250530-2' of https://git.linaro.org/people/pmaydell/qemu-arm into staging

target-arm queue:
 * hw/arm: Add GMAC devices to NPCM8XX SoC
 * hw/arm: Add missing psci_conduit to NPCM8XX SoC boot info
 * docs/interop: convert text files to restructuredText
 * target/arm: Some minor refactorings
 * tests/functional: Add a test for the Stellaris arm machines
 * hw/block: Drop unused nand.c

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmg5qPYZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3tXUD/9tKWMUEYl23gd9IB5Ee3xK
# dcgG4Fzv0Ae8HLTd1agyhrg5S2LiXmFi37IO65d8Wxf7Y2TBU+kj1m3aB/C3w9Bx
# VdHGfNsHAMuYdYCOEm9OvmuSMYSxDRd43pNWdBxbc9/MgLM24rImJ05YHoZFVGrY
# S5olcZOl3/ttFHtigO4AYAbxkHMAJ5gDyNJiuk88IPx9WGYdmmM4mzJ/m17/Re01
# hdOUi0DKQO7kl+646knSU0dicu8NeO5rBAyJzu3vFBnvYXznjd9XaxF+A0Opl54P
# aBUZz27nDLvnGQrN8B5CjevjUysko+KL/L4NRqebeQKhSe4C8tKFIDocRTGyOEoR
# SAI0UpZbcX/mXt52aksSwMNG8oRvHOqpJRnNaaCZQoMjK7SlFwi6WctDpwiGt/Hu
# WaVlXaC77YRiKf1RAgH2CxV04ts342v+bndjfi4vy8D4zbTvwgqKxg+qk3N+JBMR
# ZUI5Gz3OcGXbw5awJAYbJmyo6qxBysmdHpPY8I1eW0ohzRx1rZ3Vka4yIje5mgO+
# 5yFpSy4GDRqNYKgGwlXRaseB38qKL4bEz0+uGzXYqdG7ACBz0xhT5H10npXkX/au
# LumtwW1sohsv3Xf9oBHQ1WQel7LDcWGVEZHZn6q67mazjvivLjREvA74dq1e8bqD
# zovTStIpBYRChXTRK1ShUQ==
# =Xts4
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 30 May 2025 08:47:50 EDT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [full]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [unknown]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20250530-2' of https://git.linaro.org/people/pmaydell/qemu-arm:
  hw/block: Drop unused nand.c
  tests/functional: Add a test for the Stellaris arm machines
  target/arm/hvf: Include missing 'cpu-qom.h' header
  target/arm/kvm: Include missing 'cpu-qom.h' header
  target/arm/qmp: Include missing 'cpu.h' header
  target/arm/cpu-features: Include missing 'cpu.h' header
  hw/arm/boot: Include missing 'system/memory.h' header
  target/arm/cpregs: Include missing 'target/arm/cpu.h' header
  target/arm: Only link with zlib when TCG is enabled
  target/arm/hvf_arm: Avoid using poisoned CONFIG_HVF definition
  target/arm/tcg-stubs: compile file once (system)
  docs/interop: convert text files to restructuredText
  hw/arm: Add missing psci_conduit to NPCM8XX SoC boot info
  tests/qtest: Migrate GMAC test from 7xx to 8xx
  hw/arm: Add GMAC devices to NPCM8XX SoC

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-05-30 11:41:21 -04:00
commit 3e82ddaa8d
25 changed files with 334 additions and 969 deletions

View file

@ -510,6 +510,7 @@ Apple Silicon HVF CPUs
M: Alexander Graf <agraf@csgraf.de> M: Alexander Graf <agraf@csgraf.de>
S: Maintained S: Maintained
F: target/arm/hvf/ F: target/arm/hvf/
F: target/arm/hvf-stub.c
X86 HVF CPUs X86 HVF CPUs
M: Cameron Esfahani <dirty@apple.com> M: Cameron Esfahani <dirty@apple.com>
@ -1003,6 +1004,7 @@ F: hw/display/ssd03*
F: include/hw/input/gamepad.h F: include/hw/input/gamepad.h
F: include/hw/timer/stellaris-gptm.h F: include/hw/timer/stellaris-gptm.h
F: docs/system/arm/stellaris.rst F: docs/system/arm/stellaris.rst
F: tests/functional/test_arm_stellaris.py
STM32L4x5 SoC Family STM32L4x5 SoC Family
M: Samuel Tardieu <sam@rfc1149.net> M: Samuel Tardieu <sam@rfc1149.net>
@ -4130,7 +4132,7 @@ M: Hanna Reitz <hreitz@redhat.com>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Supported S: Supported
F: block/qcow2* F: block/qcow2*
F: docs/interop/qcow2.txt F: docs/interop/qcow2.rst
qcow qcow
M: Kevin Wolf <kwolf@redhat.com> M: Kevin Wolf <kwolf@redhat.com>

View file

@ -97,7 +97,7 @@ time.
- Persistent storage formats may impose their own requirements on bitmap names - Persistent storage formats may impose their own requirements on bitmap names
and namespaces. Presently, only qcow2 supports persistent bitmaps. See and namespaces. Presently, only qcow2 supports persistent bitmaps. See
docs/interop/qcow2.txt for more details on restrictions. Notably: :doc:`qcow2` for more details on restrictions. Notably:
- qcow2 bitmap names are limited to between 1 and 1023 bytes long. - qcow2 bitmap names are limited to between 1 and 1023 bytes long.

View file

@ -17,6 +17,7 @@ are useful for making QEMU interoperate with other software.
nbd nbd
parallels parallels
prl-xml prl-xml
qcow2
pr-helper pr-helper
qmp-spec qmp-spec
qemu-ga qemu-ga

View file

@ -1,6 +1,8 @@
== General == =======================
Qcow2 Image File Format
=======================
A qcow2 image file is organized in units of constant size, which are called A ``qcow2`` image file is organized in units of constant size, which are called
(host) clusters. A cluster is the unit in which all allocations are done, (host) clusters. A cluster is the unit in which all allocations are done,
both for actual guest data and for image metadata. both for actual guest data and for image metadata.
@ -9,10 +11,10 @@ clusters of the same size.
All numbers in qcow2 are stored in Big Endian byte order. All numbers in qcow2 are stored in Big Endian byte order.
Header
------
== Header == The first cluster of a qcow2 image contains the file header::
The first cluster of a qcow2 image contains the file header:
Byte 0 - 3: magic Byte 0 - 3: magic
QCOW magic string ("QFI\xfb") QCOW magic string ("QFI\xfb")
@ -38,7 +40,7 @@ The first cluster of a qcow2 image contains the file header:
within a cluster (1 << cluster_bits is the cluster size). within a cluster (1 << cluster_bits is the cluster size).
Must not be less than 9 (i.e. 512 byte clusters). Must not be less than 9 (i.e. 512 byte clusters).
Note: qemu as of today has an implementation limit of 2 MB Note: QEMU as of today has an implementation limit of 2 MB
as the maximum cluster size and won't be able to open images as the maximum cluster size and won't be able to open images
with larger cluster sizes. with larger cluster sizes.
@ -48,7 +50,7 @@ The first cluster of a qcow2 image contains the file header:
24 - 31: size 24 - 31: size
Virtual disk size in bytes. Virtual disk size in bytes.
Note: qemu has an implementation limit of 32 MB as Note: QEMU has an implementation limit of 32 MB as
the maximum L1 table size. With a 2 MB cluster the maximum L1 table size. With a 2 MB cluster
size, it is unable to populate a virtual cluster size, it is unable to populate a virtual cluster
beyond 2 EB (61 bits); with a 512 byte cluster beyond 2 EB (61 bits); with a 512 byte cluster
@ -87,7 +89,8 @@ The first cluster of a qcow2 image contains the file header:
For version 2, the header is exactly 72 bytes in length, and finishes here. For version 2, the header is exactly 72 bytes in length, and finishes here.
For version 3 or higher, the header length is at least 104 bytes, including For version 3 or higher, the header length is at least 104 bytes, including
the next fields through header_length. the next fields through ``header_length``.
::
72 - 79: incompatible_features 72 - 79: incompatible_features
Bitmask of incompatible features. An implementation must Bitmask of incompatible features. An implementation must
@ -185,7 +188,8 @@ the next fields through header_length.
of 8. of 8.
=== Additional fields (version 3 and higher) === Additional fields (version 3 and higher)
----------------------------------------
In general, these fields are optional and may be safely ignored by the software, In general, these fields are optional and may be safely ignored by the software,
as well as filled by zeros (which is equal to field absence), if software needs as well as filled by zeros (which is equal to field absence), if software needs
@ -193,21 +197,25 @@ to set field B, but does not care about field A which precedes B. More
formally, additional fields have the following compatibility rules: formally, additional fields have the following compatibility rules:
1. If the value of the additional field must not be ignored for correct 1. If the value of the additional field must not be ignored for correct
handling of the file, it will be accompanied by a corresponding incompatible handling of the file, it will be accompanied by a corresponding incompatible
feature bit. feature bit.
2. If there are no unrecognized incompatible feature bits set, an unknown 2. If there are no unrecognized incompatible feature bits set, an unknown
additional field may be safely ignored other than preserving its value when additional field may be safely ignored other than preserving its value when
rewriting the image header. rewriting the image header.
.. _ref_rules_3:
3. An explicit value of 0 will have the same behavior as when the field is not 3. An explicit value of 0 will have the same behavior as when the field is not
present*, if not altered by a specific incompatible bit. present*, if not altered by a specific incompatible bit.
*. A field is considered not present when header_length is less than or equal (*) A field is considered not present when ``header_length`` is less than or equal
to the field's offset. Also, all additional fields are not present for to the field's offset. Also, all additional fields are not present for
version 2. version 2.
104: compression_type ::
104: compression_type
Defines the compression method used for compressed clusters. Defines the compression method used for compressed clusters.
All compressed clusters in an image use the same compression All compressed clusters in an image use the same compression
@ -219,8 +227,8 @@ version 2.
or must be zero (which means deflate). or must be zero (which means deflate).
Available compression type values: Available compression type values:
0: deflate <https://www.ietf.org/rfc/rfc1951.txt> - 0: deflate <https://www.ietf.org/rfc/rfc1951.txt>
1: zstd <http://github.com/facebook/zstd> - 1: zstd <http://github.com/facebook/zstd>
The deflate compression type is called "zlib" The deflate compression type is called "zlib"
<https://www.zlib.net/> in QEMU. However, clusters with the <https://www.zlib.net/> in QEMU. However, clusters with the
@ -228,19 +236,21 @@ version 2.
105 - 111: Padding, contents defined below. 105 - 111: Padding, contents defined below.
=== Header padding === Header padding
--------------
@header_length must be a multiple of 8, which means that if the end of the last ``header_length`` must be a multiple of 8, which means that if the end of the last
additional field is not aligned, some padding is needed. This padding must be additional field is not aligned, some padding is needed. This padding must be
zeroed, so that if some existing (or future) additional field will fall into zeroed, so that if some existing (or future) additional field will fall into
the padding, it will be interpreted accordingly to point [3.] of the previous the padding, it will be interpreted accordingly to point `[3.] <#ref_rules_3>`_ of the previous
paragraph, i.e. in the same manner as when this field is not present. paragraph, i.e. in the same manner as when this field is not present.
=== Header extensions === Header extensions
-----------------
Directly after the image header, optional sections called header extensions can Directly after the image header, optional sections called header extensions can
be stored. Each extension has a structure like the following: be stored. Each extension has a structure like the following::
Byte 0 - 3: Header extension type: Byte 0 - 3: Header extension type:
0x00000000 - End of the header extension area 0x00000000 - End of the header extension area
@ -270,17 +280,19 @@ data of compatible features that it doesn't support. Compatible features that
need space for additional data can use a header extension. need space for additional data can use a header extension.
== String header extensions == String header extensions
------------------------
Some header extensions (such as the backing file format name and the external Some header extensions (such as the backing file format name and the external
data file name) are just a single string. In this case, the header extension data file name) are just a single string. In this case, the header extension
length is the string length and the string is not '\0' terminated. (The header length is the string length and the string is not ``\0`` terminated. (The header
extension padding can make it look like a string is '\0' terminated, but extension padding can make it look like a string is ``\0`` terminated, but
neither is padding always necessary nor is there a guarantee that zero bytes neither is padding always necessary nor is there a guarantee that zero bytes
are used for padding.) are used for padding.)
== Feature name table == Feature name table
------------------
The feature name table is an optional header extension that contains the name The feature name table is an optional header extension that contains the name
for features used by the image. It can be used by applications that don't know for features used by the image. It can be used by applications that don't know
@ -288,7 +300,7 @@ the respective feature (e.g. because the feature was introduced only later) to
display a useful error message. display a useful error message.
The number of entries in the feature name table is determined by the length of The number of entries in the feature name table is determined by the length of
the header extension data. Each entry look like this: the header extension data. Each entry looks like this::
Byte 0: Type of feature (select feature bitmap) Byte 0: Type of feature (select feature bitmap)
0: Incompatible feature 0: Incompatible feature
@ -302,7 +314,8 @@ the header extension data. Each entry look like this:
terminated if it has full length) terminated if it has full length)
== Bitmaps extension == Bitmaps extension
-----------------
The bitmaps extension is an optional header extension. It provides the ability The bitmaps extension is an optional header extension. It provides the ability
to store bitmaps related to a virtual disk. For now, there is only one bitmap to store bitmaps related to a virtual disk. For now, there is only one bitmap
@ -310,9 +323,9 @@ type: the dirty tracking bitmap, which tracks virtual disk changes from some
point in time. point in time.
The data of the extension should be considered consistent only if the The data of the extension should be considered consistent only if the
corresponding auto-clear feature bit is set, see autoclear_features above. corresponding auto-clear feature bit is set, see ``autoclear_features`` above.
The fields of the bitmaps extension are: The fields of the bitmaps extension are::
Byte 0 - 3: nb_bitmaps Byte 0 - 3: nb_bitmaps
The number of bitmaps contained in the image. Must be The number of bitmaps contained in the image. Must be
@ -331,15 +344,17 @@ The fields of the bitmaps extension are:
Offset into the image file at which the bitmap directory Offset into the image file at which the bitmap directory
starts. Must be aligned to a cluster boundary. starts. Must be aligned to a cluster boundary.
== Full disk encryption header pointer == Full disk encryption header pointer
-----------------------------------
The full disk encryption header must be present if, and only if, the The full disk encryption header must be present if, and only if, the
'crypt_method' header requires metadata. Currently this is only true ``crypt_method`` header requires metadata. Currently this is only true
of the 'LUKS' crypt method. The header extension must be absent for of the ``LUKS`` crypt method. The header extension must be absent for
other methods. other methods.
This header provides the offset at which the crypt method can store This header provides the offset at which the crypt method can store
its additional data, as well as the length of such data. its additional data, as well as the length of such data.
::
Byte 0 - 7: Offset into the image file at which the encryption Byte 0 - 7: Offset into the image file at which the encryption
header starts in bytes. Must be aligned to a cluster header starts in bytes. Must be aligned to a cluster
@ -357,10 +372,10 @@ The first 592 bytes of the header clusters will contain the LUKS
partition header. This is then followed by the key material data areas. partition header. This is then followed by the key material data areas.
The size of the key material data areas is determined by the number of The size of the key material data areas is determined by the number of
stripes in the key slot and key size. Refer to the LUKS format stripes in the key slot and key size. Refer to the LUKS format
specification ('docs/on-disk-format.pdf' in the cryptsetup source specification (``docs/on-disk-format.pdf`` in the cryptsetup source
package) for details of the LUKS partition header format. package) for details of the LUKS partition header format.
In the LUKS partition header, the "payload-offset" field will be In the LUKS partition header, the ``payload-offset`` field will be
calculated as normal for the LUKS spec. ie the size of the LUKS calculated as normal for the LUKS spec. ie the size of the LUKS
header, plus key material regions, plus padding, relative to the header, plus key material regions, plus padding, relative to the
start of the LUKS header. This offset value is not required to be start of the LUKS header. This offset value is not required to be
@ -369,11 +384,12 @@ context of qcow2, since the qcow2 file format itself defines where
the real payload offset is, but none the less a valid payload offset the real payload offset is, but none the less a valid payload offset
should always be present. should always be present.
In the LUKS key slots header, the "key-material-offset" is relative In the LUKS key slots header, the ``key-material-offset`` is relative
to the start of the LUKS header clusters in the qcow2 container, to the start of the LUKS header clusters in the qcow2 container,
not the start of the qcow2 file. not the start of the qcow2 file.
Logically the layout looks like Logically the layout looks like
::
+-----------------------------+ +-----------------------------+
| QCow2 header | | QCow2 header |
@ -405,7 +421,8 @@ Logically the layout looks like
| | | |
+-----------------------------+ +-----------------------------+
== Data encryption == Data encryption
---------------
When an encryption method is requested in the header, the image payload When an encryption method is requested in the header, the image payload
data must be encrypted/decrypted on every write/read. The image headers data must be encrypted/decrypted on every write/read. The image headers
@ -413,7 +430,7 @@ and metadata are never encrypted.
The algorithms used for encryption vary depending on the method The algorithms used for encryption vary depending on the method
- AES: - ``AES``:
The AES cipher, in CBC mode, with 256 bit keys. The AES cipher, in CBC mode, with 256 bit keys.
@ -425,7 +442,7 @@ The algorithms used for encryption vary depending on the method
supported in the command line tools for the sake of back compatibility supported in the command line tools for the sake of back compatibility
and data liberation. and data liberation.
- LUKS: - ``LUKS``:
The algorithms are specified in the LUKS header. The algorithms are specified in the LUKS header.
@ -433,7 +450,8 @@ The algorithms used for encryption vary depending on the method
in the LUKS header, with the physical disk sector as the in the LUKS header, with the physical disk sector as the
input tweak. input tweak.
== Host cluster management == Host cluster management
-----------------------
qcow2 manages the allocation of host clusters by maintaining a reference count qcow2 manages the allocation of host clusters by maintaining a reference count
for each host cluster. A refcount of 0 means that the cluster is free, 1 means for each host cluster. A refcount of 0 means that the cluster is free, 1 means
@ -453,14 +471,15 @@ Although a large enough refcount table can reserve clusters past 64 PB
large), note that some qcow2 metadata such as L1/L2 tables must point large), note that some qcow2 metadata such as L1/L2 tables must point
to clusters prior to that point. to clusters prior to that point.
Note: qemu has an implementation limit of 8 MB as the maximum refcount .. note::
table size. With a 2 MB cluster size and a default refcount_order of QEMU has an implementation limit of 8 MB as the maximum refcount
4, it is unable to reference host resources beyond 2 EB (61 bits); in table size. With a 2 MB cluster size and a default refcount_order of
the worst case, with a 512 cluster size and refcount_order of 6, it is 4, it is unable to reference host resources beyond 2 EB (61 bits); in
unable to access beyond 32 GB (35 bits). the worst case, with a 512 cluster size and refcount_order of 6, it is
unable to access beyond 32 GB (35 bits).
Given an offset into the image file, the refcount of its cluster can be Given an offset into the image file, the refcount of its cluster can be
obtained as follows: obtained as follows::
refcount_block_entries = (cluster_size * 8 / refcount_bits) refcount_block_entries = (cluster_size * 8 / refcount_bits)
@ -470,7 +489,7 @@ obtained as follows:
refcount_block = load_cluster(refcount_table[refcount_table_index]); refcount_block = load_cluster(refcount_table[refcount_table_index]);
return refcount_block[refcount_block_index]; return refcount_block[refcount_block_index];
Refcount table entry: Refcount table entry::
Bit 0 - 8: Reserved (set to 0) Bit 0 - 8: Reserved (set to 0)
@ -482,14 +501,15 @@ Refcount table entry:
been allocated. All refcounts managed by this refcount block been allocated. All refcounts managed by this refcount block
are 0. are 0.
Refcount block entry (x = refcount_bits - 1): Refcount block entry ``(x = refcount_bits - 1)``::
Bit 0 - x: Reference count of the cluster. If refcount_bits implies a Bit 0 - x: Reference count of the cluster. If refcount_bits implies a
sub-byte width, note that bit 0 means the least significant sub-byte width, note that bit 0 means the least significant
bit in this context. bit in this context.
== Cluster mapping == Cluster mapping
---------------
Just as for refcounts, qcow2 uses a two-level structure for the mapping of Just as for refcounts, qcow2 uses a two-level structure for the mapping of
guest clusters to host clusters. They are called L1 and L2 table. guest clusters to host clusters. They are called L1 and L2 table.
@ -509,7 +529,7 @@ compressed clusters to reside below 512 TB (49 bits), and this limit
cannot be relaxed without an incompatible layout change). cannot be relaxed without an incompatible layout change).
Given an offset into the virtual disk, the offset into the image file can be Given an offset into the virtual disk, the offset into the image file can be
obtained as follows: obtained as follows::
l2_entries = (cluster_size / sizeof(uint64_t)) [*] l2_entries = (cluster_size / sizeof(uint64_t)) [*]
@ -523,7 +543,7 @@ obtained as follows:
[*] this changes if Extended L2 Entries are enabled, see next section [*] this changes if Extended L2 Entries are enabled, see next section
L1 table entry: L1 table entry::
Bit 0 - 8: Reserved (set to 0) Bit 0 - 8: Reserved (set to 0)
@ -538,7 +558,7 @@ L1 table entry:
refcount is exactly one. This information is only accurate refcount is exactly one. This information is only accurate
in the active L1 table. in the active L1 table.
L2 table entry: L2 table entry::
Bit 0 - 61: Cluster descriptor Bit 0 - 61: Cluster descriptor
@ -555,7 +575,7 @@ L2 table entry:
mapping for guest cluster offsets), so this bit should be 1 mapping for guest cluster offsets), so this bit should be 1
for all allocated clusters. for all allocated clusters.
Standard Cluster Descriptor: Standard Cluster Descriptor::
Bit 0: If set to 1, the cluster reads as all zeros. The host Bit 0: If set to 1, the cluster reads as all zeros. The host
cluster offset can be used to describe a preallocation, cluster offset can be used to describe a preallocation,
@ -577,7 +597,7 @@ Standard Cluster Descriptor:
56 - 61: Reserved (set to 0) 56 - 61: Reserved (set to 0)
Compressed Clusters Descriptor (x = 62 - (cluster_bits - 8)): Compressed Clusters Descriptor ``(x = 62 - (cluster_bits - 8))``::
Bit 0 - x-1: Host cluster offset. This is usually _not_ aligned to a Bit 0 - x-1: Host cluster offset. This is usually _not_ aligned to a
cluster or sector boundary! If cluster_bits is cluster or sector boundary! If cluster_bits is
@ -601,7 +621,8 @@ file (except if bit 0 in the Standard Cluster Descriptor is set). If there is
no backing file or the backing file is smaller than the image, they shall read no backing file or the backing file is smaller than the image, they shall read
zeros for all parts that are not covered by the backing file. zeros for all parts that are not covered by the backing file.
== Extended L2 Entries == Extended L2 Entries
-------------------
An image uses Extended L2 Entries if bit 4 is set on the incompatible_features An image uses Extended L2 Entries if bit 4 is set on the incompatible_features
field of the header. field of the header.
@ -615,6 +636,8 @@ subclusters so they are treated the same as in images without this feature.
The size of an extended L2 entry is 128 bits so the number of entries per table The size of an extended L2 entry is 128 bits so the number of entries per table
is calculated using this formula: is calculated using this formula:
.. code::
l2_entries = (cluster_size / (2 * sizeof(uint64_t))) l2_entries = (cluster_size / (2 * sizeof(uint64_t)))
The first 64 bits have the same format as the standard L2 table entry described The first 64 bits have the same format as the standard L2 table entry described
@ -623,7 +646,7 @@ descriptor.
The last 64 bits contain a subcluster allocation bitmap with this format: The last 64 bits contain a subcluster allocation bitmap with this format:
Subcluster Allocation Bitmap (for standard clusters): Subcluster Allocation Bitmap (for standard clusters)::
Bit 0 - 31: Allocation status (one bit per subcluster) Bit 0 - 31: Allocation status (one bit per subcluster)
@ -647,13 +670,14 @@ Subcluster Allocation Bitmap (for standard clusters):
Bits are assigned starting from the least significant Bits are assigned starting from the least significant
one (i.e. bit x is used for subcluster x - 32). one (i.e. bit x is used for subcluster x - 32).
Subcluster Allocation Bitmap (for compressed clusters): Subcluster Allocation Bitmap (for compressed clusters)::
Bit 0 - 63: Reserved (set to 0) Bit 0 - 63: Reserved (set to 0)
Compressed clusters don't have subclusters, Compressed clusters don't have subclusters,
so this field is not used. so this field is not used.
== Snapshots == Snapshots
---------
qcow2 supports internal snapshots. Their basic principle of operation is to qcow2 supports internal snapshots. Their basic principle of operation is to
switch the active L1 table, so that a different set of host clusters are switch the active L1 table, so that a different set of host clusters are
@ -672,7 +696,7 @@ in the image file, whose starting offset and length are given by the header
fields snapshots_offset and nb_snapshots. The entries of the snapshot table fields snapshots_offset and nb_snapshots. The entries of the snapshot table
have variable length, depending on the length of ID, name and extra data. have variable length, depending on the length of ID, name and extra data.
Snapshot table entry: Snapshot table entry::
Byte 0 - 7: Offset into the image file at which the L1 table for the Byte 0 - 7: Offset into the image file at which the L1 table for the
snapshot starts. Must be aligned to a cluster boundary. snapshot starts. Must be aligned to a cluster boundary.
@ -728,7 +752,8 @@ Snapshot table entry:
next multiple of 8. next multiple of 8.
== Bitmaps == Bitmaps
-------
As mentioned above, the bitmaps extension provides the ability to store bitmaps As mentioned above, the bitmaps extension provides the ability to store bitmaps
related to a virtual disk. This section describes how these bitmaps are stored. related to a virtual disk. This section describes how these bitmaps are stored.
@ -739,20 +764,23 @@ each bitmap size is equal to the virtual disk size.
Each bit of the bitmap is responsible for strictly defined range of the virtual Each bit of the bitmap is responsible for strictly defined range of the virtual
disk. For bit number bit_nr the corresponding range (in bytes) will be: disk. For bit number bit_nr the corresponding range (in bytes) will be:
.. code::
[bit_nr * bitmap_granularity .. (bit_nr + 1) * bitmap_granularity - 1] [bit_nr * bitmap_granularity .. (bit_nr + 1) * bitmap_granularity - 1]
Granularity is a property of the concrete bitmap, see below. Granularity is a property of the concrete bitmap, see below.
=== Bitmap directory === Bitmap directory
----------------
Each bitmap saved in the image is described in a bitmap directory entry. The Each bitmap saved in the image is described in a bitmap directory entry. The
bitmap directory is a contiguous area in the image file, whose starting offset bitmap directory is a contiguous area in the image file, whose starting offset
and length are given by the header extension fields bitmap_directory_offset and and length are given by the header extension fields ``bitmap_directory_offset`` and
bitmap_directory_size. The entries of the bitmap directory have variable ``bitmap_directory_size``. The entries of the bitmap directory have variable
length, depending on the lengths of the bitmap name and extra data. length, depending on the lengths of the bitmap name and extra data.
Structure of a bitmap directory entry: Structure of a bitmap directory entry::
Byte 0 - 7: bitmap_table_offset Byte 0 - 7: bitmap_table_offset
Offset into the image file at which the bitmap table Offset into the image file at which the bitmap table
@ -833,7 +861,8 @@ Structure of a bitmap directory entry:
next multiple of 8. All bytes of the padding must be zero. next multiple of 8. All bytes of the padding must be zero.
=== Bitmap table === Bitmap table
------------
Each bitmap is stored using a one-level structure (as opposed to two-level Each bitmap is stored using a one-level structure (as opposed to two-level
structures like for refcounts and guest clusters mapping) for the mapping of structures like for refcounts and guest clusters mapping) for the mapping of
@ -843,7 +872,7 @@ Each bitmap table has a variable size (stored in the bitmap directory entry)
and may use multiple clusters, however, it must be contiguous in the image and may use multiple clusters, however, it must be contiguous in the image
file. file.
Structure of a bitmap table entry: Structure of a bitmap table entry::
Bit 0: Reserved and must be zero if bits 9 - 55 are non-zero. Bit 0: Reserved and must be zero if bits 9 - 55 are non-zero.
If bits 9 - 55 are zero: If bits 9 - 55 are zero:
@ -860,11 +889,12 @@ Structure of a bitmap table entry:
56 - 63: Reserved and must be zero. 56 - 63: Reserved and must be zero.
=== Bitmap data === Bitmap data
-----------
As noted above, bitmap data is stored in separate clusters, described by the As noted above, bitmap data is stored in separate clusters, described by the
bitmap table. Given an offset (in bytes) into the bitmap data, the offset into bitmap table. Given an offset (in bytes) into the bitmap data, the offset into
the image file can be obtained as follows: the image file can be obtained as follows::
image_offset(bitmap_data_offset) = image_offset(bitmap_data_offset) =
bitmap_table[bitmap_data_offset / cluster_size] + bitmap_table[bitmap_data_offset / cluster_size] +
@ -875,7 +905,7 @@ above).
Given an offset byte_nr into the virtual disk and the bitmap's granularity, the Given an offset byte_nr into the virtual disk and the bitmap's granularity, the
bit offset into the image file to the corresponding bit of the bitmap can be bit offset into the image file to the corresponding bit of the bitmap can be
calculated like this: calculated like this::
bit_offset(byte_nr) = bit_offset(byte_nr) =
image_offset(byte_nr / granularity / 8) * 8 + image_offset(byte_nr / granularity / 8) * 8 +
@ -886,21 +916,22 @@ last cluster of the bitmap data contains some unused tail bits. These bits must
be zero. be zero.
=== Dirty tracking bitmaps === Dirty tracking bitmaps
----------------------
Bitmaps with 'type' field equal to one are dirty tracking bitmaps. Bitmaps with ``type`` field equal to one are dirty tracking bitmaps.
When the virtual disk is in use dirty tracking bitmap may be 'enabled' or When the virtual disk is in use dirty tracking bitmap may be ``enabled`` or
'disabled'. While the bitmap is 'enabled', all writes to the virtual disk ``disabled``. While the bitmap is ``enabled``, all writes to the virtual disk
should be reflected in the bitmap. A set bit in the bitmap means that the should be reflected in the bitmap. A set bit in the bitmap means that the
corresponding range of the virtual disk (see above) was written to while the corresponding range of the virtual disk (see above) was written to while the
bitmap was 'enabled'. An unset bit means that this range was not written to. bitmap was ``enabled``. An unset bit means that this range was not written to.
The software doesn't have to sync the bitmap in the image file with its The software doesn't have to sync the bitmap in the image file with its
representation in RAM after each write or metadata change. Flag 'in_use' representation in RAM after each write or metadata change. Flag ``in_use``
should be set while the bitmap is not synced. should be set while the bitmap is not synced.
In the image file the 'enabled' state is reflected by the 'auto' flag. If this In the image file the ``enabled`` state is reflected by the ``auto`` flag. If this
flag is set, the software must consider the bitmap as 'enabled' and start flag is set, the software must consider the bitmap as ``enabled`` and start
tracking virtual disk changes to this bitmap from the first write to the tracking virtual disk changes to this bitmap from the first write to the
virtual disk. If this flag is not set then the bitmap is disabled. virtual disk. If this flag is not set then the bitmap is disabled.

View file

@ -15,7 +15,7 @@ not a straightforward operation.
This document attempts to give an overview of the L2 and refcount This document attempts to give an overview of the L2 and refcount
caches, and how to configure them. caches, and how to configure them.
Please refer to the docs/interop/qcow2.txt file for an in-depth Please refer to the docs/interop/qcow2.rst file for an in-depth
technical description of the qcow2 file format. technical description of the qcow2 file format.

View file

@ -147,7 +147,6 @@ config OMAP
bool bool
select FRAMEBUFFER select FRAMEBUFFER
select I2C select I2C
select NAND
select PFLASH_CFI01 select PFLASH_CFI01
select SD select SD
select SERIAL_MM select SERIAL_MM

View file

@ -19,6 +19,7 @@
#include "system/kvm.h" #include "system/kvm.h"
#include "system/tcg.h" #include "system/tcg.h"
#include "system/system.h" #include "system/system.h"
#include "system/memory.h"
#include "system/numa.h" #include "system/numa.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "system/reset.h" #include "system/reset.h"

View file

@ -67,6 +67,9 @@
/* SDHCI Modules */ /* SDHCI Modules */
#define NPCM8XX_MMC_BA 0xf0842000 #define NPCM8XX_MMC_BA 0xf0842000
/* PCS Module */
#define NPCM8XX_PCS_BA 0xf0780000
/* PSPI Modules */ /* PSPI Modules */
#define NPCM8XX_PSPI_BA 0xf0201000 #define NPCM8XX_PSPI_BA 0xf0201000
@ -85,6 +88,10 @@ enum NPCM8xxInterrupt {
NPCM8XX_ADC_IRQ = 0, NPCM8XX_ADC_IRQ = 0,
NPCM8XX_PECI_IRQ = 6, NPCM8XX_PECI_IRQ = 6,
NPCM8XX_KCS_HIB_IRQ = 9, NPCM8XX_KCS_HIB_IRQ = 9,
NPCM8XX_GMAC1_IRQ = 14,
NPCM8XX_GMAC2_IRQ,
NPCM8XX_GMAC3_IRQ,
NPCM8XX_GMAC4_IRQ,
NPCM8XX_MMC_IRQ = 26, NPCM8XX_MMC_IRQ = 26,
NPCM8XX_PSPI_IRQ = 28, NPCM8XX_PSPI_IRQ = 28,
NPCM8XX_TIMER0_IRQ = 32, /* Timer Module 0 */ NPCM8XX_TIMER0_IRQ = 32, /* Timer Module 0 */
@ -260,6 +267,14 @@ static const hwaddr npcm8xx_smbus_addr[] = {
0xfff0a000, 0xfff0a000,
}; };
/* Register base address for each GMAC Module */
static const hwaddr npcm8xx_gmac_addr[] = {
0xf0802000,
0xf0804000,
0xf0806000,
0xf0808000,
};
/* Register base address for each USB host EHCI registers */ /* Register base address for each USB host EHCI registers */
static const hwaddr npcm8xx_ehci_addr[] = { static const hwaddr npcm8xx_ehci_addr[] = {
0xf0828100, 0xf0828100,
@ -350,6 +365,7 @@ static struct arm_boot_info npcm8xx_binfo = {
.secure_boot = false, .secure_boot = false,
.board_id = -1, .board_id = -1,
.board_setup_addr = NPCM8XX_BOARD_SETUP_ADDR, .board_setup_addr = NPCM8XX_BOARD_SETUP_ADDR,
.psci_conduit = QEMU_PSCI_CONDUIT_SMC,
}; };
void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc) void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc)
@ -444,6 +460,11 @@ static void npcm8xx_init(Object *obj)
object_initialize_child(obj, "mft[*]", &s->mft[i], TYPE_NPCM7XX_MFT); object_initialize_child(obj, "mft[*]", &s->mft[i], TYPE_NPCM7XX_MFT);
} }
for (i = 0; i < ARRAY_SIZE(s->gmac); i++) {
object_initialize_child(obj, "gmac[*]", &s->gmac[i], TYPE_NPCM_GMAC);
}
object_initialize_child(obj, "pcs", &s->pcs, TYPE_NPCM_PCS);
object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI); object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
object_initialize_child(obj, "pspi", &s->pspi, TYPE_NPCM_PSPI); object_initialize_child(obj, "pspi", &s->pspi, TYPE_NPCM_PSPI);
} }
@ -668,6 +689,35 @@ static void npcm8xx_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(sbd, 0, npcm8xx_irq(s, NPCM8XX_MFT0_IRQ + i)); sysbus_connect_irq(sbd, 0, npcm8xx_irq(s, NPCM8XX_MFT0_IRQ + i));
} }
/*
* GMAC Modules. Cannot fail.
*/
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_gmac_addr) != ARRAY_SIZE(s->gmac));
for (i = 0; i < ARRAY_SIZE(s->gmac); i++) {
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->gmac[i]);
/* This is used to make sure that the NIC can create the device */
qemu_configure_nic_device(DEVICE(sbd), false, NULL);
/*
* The device exists regardless of whether it's connected to a QEMU
* netdev backend. So always instantiate it even if there is no
* backend.
*/
sysbus_realize(sbd, &error_abort);
sysbus_mmio_map(sbd, 0, npcm8xx_gmac_addr[i]);
/*
* N.B. The values for the second argument sysbus_connect_irq are
* chosen to match the registration order in npcm7xx_emc_realize.
*/
sysbus_connect_irq(sbd, 0, npcm8xx_irq(s, NPCM8XX_GMAC1_IRQ + i));
}
/*
* GMAC Physical Coding Sublayer(PCS) Module. Cannot fail.
*/
sysbus_realize(SYS_BUS_DEVICE(&s->pcs), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcs), 0, NPCM8XX_PCS_BA);
/* /*
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
* specified, but this is a programming error. * specified, but this is a programming error.
@ -741,12 +791,7 @@ static void npcm8xx_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("npcm8xx.ahbpci", 0xf0400000, 1 * MiB); create_unimplemented_device("npcm8xx.ahbpci", 0xf0400000, 1 * MiB);
create_unimplemented_device("npcm8xx.dap", 0xf0500000, 960 * KiB); create_unimplemented_device("npcm8xx.dap", 0xf0500000, 960 * KiB);
create_unimplemented_device("npcm8xx.mcphy", 0xf05f0000, 64 * KiB); create_unimplemented_device("npcm8xx.mcphy", 0xf05f0000, 64 * KiB);
create_unimplemented_device("npcm8xx.pcs", 0xf0780000, 256 * KiB);
create_unimplemented_device("npcm8xx.tsgen", 0xf07fc000, 8 * KiB); create_unimplemented_device("npcm8xx.tsgen", 0xf07fc000, 8 * KiB);
create_unimplemented_device("npcm8xx.gmac1", 0xf0802000, 8 * KiB);
create_unimplemented_device("npcm8xx.gmac2", 0xf0804000, 8 * KiB);
create_unimplemented_device("npcm8xx.gmac3", 0xf0806000, 8 * KiB);
create_unimplemented_device("npcm8xx.gmac4", 0xf0808000, 8 * KiB);
create_unimplemented_device("npcm8xx.copctl", 0xf080c000, 4 * KiB); create_unimplemented_device("npcm8xx.copctl", 0xf080c000, 4 * KiB);
create_unimplemented_device("npcm8xx.tipctl", 0xf080d000, 4 * KiB); create_unimplemented_device("npcm8xx.tipctl", 0xf080d000, 4 * KiB);
create_unimplemented_device("npcm8xx.rst", 0xf080e000, 4 * KiB); create_unimplemented_device("npcm8xx.rst", 0xf080e000, 4 * KiB);

View file

@ -13,9 +13,6 @@ config FDC_SYSBUS
config SSI_M25P80 config SSI_M25P80
bool bool
config NAND
bool
config PFLASH_CFI01 config PFLASH_CFI01
bool bool

View file

@ -6,7 +6,6 @@ system_ss.add(files(
system_ss.add(when: 'CONFIG_FDC', if_true: files('fdc.c')) system_ss.add(when: 'CONFIG_FDC', if_true: files('fdc.c'))
system_ss.add(when: 'CONFIG_FDC_ISA', if_true: files('fdc-isa.c')) system_ss.add(when: 'CONFIG_FDC_ISA', if_true: files('fdc-isa.c'))
system_ss.add(when: 'CONFIG_FDC_SYSBUS', if_true: files('fdc-sysbus.c')) system_ss.add(when: 'CONFIG_FDC_SYSBUS', if_true: files('fdc-sysbus.c'))
system_ss.add(when: 'CONFIG_NAND', if_true: files('nand.c'))
system_ss.add(when: 'CONFIG_PFLASH_CFI01', if_true: files('pflash_cfi01.c')) system_ss.add(when: 'CONFIG_PFLASH_CFI01', if_true: files('pflash_cfi01.c'))
system_ss.add(when: 'CONFIG_PFLASH_CFI02', if_true: files('pflash_cfi02.c')) system_ss.add(when: 'CONFIG_PFLASH_CFI02', if_true: files('pflash_cfi02.c'))
system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c')) system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c'))

View file

@ -1,835 +0,0 @@
/*
* Flash NAND memory emulation. Based on "16M x 8 Bit NAND Flash
* Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
* Samsung Electronic.
*
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
* Support for additional features based on "MT29F2G16ABCWP 2Gx16"
* datasheet from Micron Technology and "NAND02G-B2C" datasheet
* from ST Microelectronics.
*
* This code is licensed under the GNU GPL v2.
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#ifndef NAND_IO
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "hw/block/flash.h"
#include "system/block-backend.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qom/object.h"
# define NAND_CMD_READ0 0x00
# define NAND_CMD_READ1 0x01
# define NAND_CMD_READ2 0x50
# define NAND_CMD_LPREAD2 0x30
# define NAND_CMD_NOSERIALREAD2 0x35
# define NAND_CMD_RANDOMREAD1 0x05
# define NAND_CMD_RANDOMREAD2 0xe0
# define NAND_CMD_READID 0x90
# define NAND_CMD_RESET 0xff
# define NAND_CMD_PAGEPROGRAM1 0x80
# define NAND_CMD_PAGEPROGRAM2 0x10
# define NAND_CMD_CACHEPROGRAM2 0x15
# define NAND_CMD_BLOCKERASE1 0x60
# define NAND_CMD_BLOCKERASE2 0xd0
# define NAND_CMD_READSTATUS 0x70
# define NAND_CMD_COPYBACKPRG1 0x85
# define NAND_IOSTATUS_ERROR (1 << 0)
# define NAND_IOSTATUS_PLANE0 (1 << 1)
# define NAND_IOSTATUS_PLANE1 (1 << 2)
# define NAND_IOSTATUS_PLANE2 (1 << 3)
# define NAND_IOSTATUS_PLANE3 (1 << 4)
# define NAND_IOSTATUS_READY (1 << 6)
# define NAND_IOSTATUS_UNPROTCT (1 << 7)
# define MAX_PAGE 0x800
# define MAX_OOB 0x40
typedef struct NANDFlashState NANDFlashState;
struct NANDFlashState {
DeviceState parent_obj;
uint8_t manf_id, chip_id;
uint8_t buswidth; /* in BYTES */
int size, pages;
int page_shift, oob_shift, erase_shift, addr_shift;
uint8_t *storage;
BlockBackend *blk;
int mem_oob;
uint8_t cle, ale, ce, wp, gnd;
uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
uint8_t *ioaddr;
int iolen;
uint32_t cmd;
uint64_t addr;
int addrlen;
int status;
int offset;
void (*blk_write)(NANDFlashState *s);
void (*blk_erase)(NANDFlashState *s);
/*
* Returns %true when block containing (@addr + @offset) is
* successfully loaded, otherwise %false.
*/
bool (*blk_load)(NANDFlashState *s, uint64_t addr, unsigned offset);
uint32_t ioaddr_vmstate;
};
#define TYPE_NAND "nand"
OBJECT_DECLARE_SIMPLE_TYPE(NANDFlashState, NAND)
static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
{
/* Like memcpy() but we logical-AND the data into the destination */
int i;
for (i = 0; i < n; i++) {
dest[i] &= src[i];
}
}
# define NAND_NO_AUTOINCR 0x00000001
# define NAND_BUSWIDTH_16 0x00000002
# define NAND_NO_PADDING 0x00000004
# define NAND_CACHEPRG 0x00000008
# define NAND_COPYBACK 0x00000010
# define NAND_IS_AND 0x00000020
# define NAND_4PAGE_ARRAY 0x00000040
# define NAND_NO_READRDY 0x00000100
# define NAND_SAMSUNG_LP (NAND_NO_PADDING | NAND_COPYBACK)
# define NAND_IO
# define PAGE(addr) ((addr) >> ADDR_SHIFT)
# define PAGE_START(page) (PAGE(page) * (NAND_PAGE_SIZE + OOB_SIZE))
# define PAGE_MASK ((1 << ADDR_SHIFT) - 1)
# define OOB_SHIFT (PAGE_SHIFT - 5)
# define OOB_SIZE (1 << OOB_SHIFT)
# define SECTOR(addr) ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
# define SECTOR_OFFSET(addr) ((addr) & ((511 >> PAGE_SHIFT) << 8))
# define NAND_PAGE_SIZE 256
# define PAGE_SHIFT 8
# define PAGE_SECTORS 1
# define ADDR_SHIFT 8
# include "nand.c"
# define NAND_PAGE_SIZE 512
# define PAGE_SHIFT 9
# define PAGE_SECTORS 1
# define ADDR_SHIFT 8
# include "nand.c"
# define NAND_PAGE_SIZE 2048
# define PAGE_SHIFT 11
# define PAGE_SECTORS 4
# define ADDR_SHIFT 16
# include "nand.c"
/* Information based on Linux drivers/mtd/nand/raw/nand_ids.c */
static const struct {
int size;
int width;
int page_shift;
int erase_shift;
uint32_t options;
} nand_flash_ids[0x100] = {
[0 ... 0xff] = { 0 },
[0x6b] = { 4, 8, 9, 4, 0 },
[0xe3] = { 4, 8, 9, 4, 0 },
[0xe5] = { 4, 8, 9, 4, 0 },
[0xd6] = { 8, 8, 9, 4, 0 },
[0xe6] = { 8, 8, 9, 4, 0 },
[0x33] = { 16, 8, 9, 5, 0 },
[0x73] = { 16, 8, 9, 5, 0 },
[0x43] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x53] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x35] = { 32, 8, 9, 5, 0 },
[0x75] = { 32, 8, 9, 5, 0 },
[0x45] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x55] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x36] = { 64, 8, 9, 5, 0 },
[0x76] = { 64, 8, 9, 5, 0 },
[0x46] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x56] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x78] = { 128, 8, 9, 5, 0 },
[0x39] = { 128, 8, 9, 5, 0 },
[0x79] = { 128, 8, 9, 5, 0 },
[0x72] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x49] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x74] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x59] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 },
[0x71] = { 256, 8, 9, 5, 0 },
/*
* These are the new chips with large page size. The pagesize and the
* erasesize is determined from the extended id bytes
*/
# define LP_OPTIONS (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)
# define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
/* 512 Megabit */
[0xa2] = { 64, 8, 0, 0, LP_OPTIONS },
[0xf2] = { 64, 8, 0, 0, LP_OPTIONS },
[0xb2] = { 64, 16, 0, 0, LP_OPTIONS16 },
[0xc2] = { 64, 16, 0, 0, LP_OPTIONS16 },
/* 1 Gigabit */
[0xa1] = { 128, 8, 0, 0, LP_OPTIONS },
[0xf1] = { 128, 8, 0, 0, LP_OPTIONS },
[0xb1] = { 128, 16, 0, 0, LP_OPTIONS16 },
[0xc1] = { 128, 16, 0, 0, LP_OPTIONS16 },
/* 2 Gigabit */
[0xaa] = { 256, 8, 0, 0, LP_OPTIONS },
[0xda] = { 256, 8, 0, 0, LP_OPTIONS },
[0xba] = { 256, 16, 0, 0, LP_OPTIONS16 },
[0xca] = { 256, 16, 0, 0, LP_OPTIONS16 },
/* 4 Gigabit */
[0xac] = { 512, 8, 0, 0, LP_OPTIONS },
[0xdc] = { 512, 8, 0, 0, LP_OPTIONS },
[0xbc] = { 512, 16, 0, 0, LP_OPTIONS16 },
[0xcc] = { 512, 16, 0, 0, LP_OPTIONS16 },
/* 8 Gigabit */
[0xa3] = { 1024, 8, 0, 0, LP_OPTIONS },
[0xd3] = { 1024, 8, 0, 0, LP_OPTIONS },
[0xb3] = { 1024, 16, 0, 0, LP_OPTIONS16 },
[0xc3] = { 1024, 16, 0, 0, LP_OPTIONS16 },
/* 16 Gigabit */
[0xa5] = { 2048, 8, 0, 0, LP_OPTIONS },
[0xd5] = { 2048, 8, 0, 0, LP_OPTIONS },
[0xb5] = { 2048, 16, 0, 0, LP_OPTIONS16 },
[0xc5] = { 2048, 16, 0, 0, LP_OPTIONS16 },
};
static void nand_reset(DeviceState *dev)
{
NANDFlashState *s = NAND(dev);
s->cmd = NAND_CMD_READ0;
s->addr = 0;
s->addrlen = 0;
s->iolen = 0;
s->offset = 0;
s->status &= NAND_IOSTATUS_UNPROTCT;
s->status |= NAND_IOSTATUS_READY;
}
static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
{
s->ioaddr[s->iolen++] = value;
for (value = s->buswidth; --value;) {
s->ioaddr[s->iolen++] = 0;
}
}
/*
* nand_load_block: Load block containing (s->addr + @offset).
* Returns length of data available at @offset in this block.
*/
static unsigned nand_load_block(NANDFlashState *s, unsigned offset)
{
unsigned iolen;
if (!s->blk_load(s, s->addr, offset)) {
return 0;
}
iolen = (1 << s->page_shift);
if (s->gnd) {
iolen += 1 << s->oob_shift;
}
assert(offset <= iolen);
iolen -= offset;
return iolen;
}
static void nand_command(NANDFlashState *s)
{
switch (s->cmd) {
case NAND_CMD_READ0:
s->iolen = 0;
break;
case NAND_CMD_READID:
s->ioaddr = s->io;
s->iolen = 0;
nand_pushio_byte(s, s->manf_id);
nand_pushio_byte(s, s->chip_id);
nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
/* Page Size, Block Size, Spare Size; bit 6 indicates
* 8 vs 16 bit width NAND.
*/
nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
} else {
nand_pushio_byte(s, 0xc0); /* Multi-plane */
}
break;
case NAND_CMD_RANDOMREAD2:
case NAND_CMD_NOSERIALREAD2:
if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
break;
s->iolen = nand_load_block(s, s->addr & ((1 << s->addr_shift) - 1));
break;
case NAND_CMD_RESET:
nand_reset(DEVICE(s));
break;
case NAND_CMD_PAGEPROGRAM1:
s->ioaddr = s->io;
s->iolen = 0;
break;
case NAND_CMD_PAGEPROGRAM2:
if (s->wp) {
s->blk_write(s);
}
break;
case NAND_CMD_BLOCKERASE1:
break;
case NAND_CMD_BLOCKERASE2:
s->addr &= (1ull << s->addrlen * 8) - 1;
s->addr <<= nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP ?
16 : 8;
if (s->wp) {
s->blk_erase(s);
}
break;
case NAND_CMD_READSTATUS:
s->ioaddr = s->io;
s->iolen = 0;
nand_pushio_byte(s, s->status);
break;
default:
printf("%s: Unknown NAND command 0x%02x\n", __func__, s->cmd);
}
}
static int nand_pre_save(void *opaque)
{
NANDFlashState *s = NAND(opaque);
s->ioaddr_vmstate = s->ioaddr - s->io;
return 0;
}
static int nand_post_load(void *opaque, int version_id)
{
NANDFlashState *s = NAND(opaque);
if (s->ioaddr_vmstate > sizeof(s->io)) {
return -EINVAL;
}
s->ioaddr = s->io + s->ioaddr_vmstate;
return 0;
}
static const VMStateDescription vmstate_nand = {
.name = "nand",
.version_id = 1,
.minimum_version_id = 1,
.pre_save = nand_pre_save,
.post_load = nand_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT8(cle, NANDFlashState),
VMSTATE_UINT8(ale, NANDFlashState),
VMSTATE_UINT8(ce, NANDFlashState),
VMSTATE_UINT8(wp, NANDFlashState),
VMSTATE_UINT8(gnd, NANDFlashState),
VMSTATE_BUFFER(io, NANDFlashState),
VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
VMSTATE_INT32(iolen, NANDFlashState),
VMSTATE_UINT32(cmd, NANDFlashState),
VMSTATE_UINT64(addr, NANDFlashState),
VMSTATE_INT32(addrlen, NANDFlashState),
VMSTATE_INT32(status, NANDFlashState),
VMSTATE_INT32(offset, NANDFlashState),
/* XXX: do we want to save s->storage too? */
VMSTATE_END_OF_LIST()
}
};
static void nand_realize(DeviceState *dev, Error **errp)
{
int pagesize;
NANDFlashState *s = NAND(dev);
int ret;
s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
s->size = nand_flash_ids[s->chip_id].size << 20;
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
s->page_shift = 11;
s->erase_shift = 6;
} else {
s->page_shift = nand_flash_ids[s->chip_id].page_shift;
s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
}
switch (1 << s->page_shift) {
case 256:
nand_init_256(s);
break;
case 512:
nand_init_512(s);
break;
case 2048:
nand_init_2048(s);
break;
default:
error_setg(errp, "Unsupported NAND block size %#x",
1 << s->page_shift);
return;
}
pagesize = 1 << s->oob_shift;
s->mem_oob = 1;
if (s->blk) {
if (!blk_supports_write_perm(s->blk)) {
error_setg(errp, "Can't use a read-only drive");
return;
}
ret = blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
BLK_PERM_ALL, errp);
if (ret < 0) {
return;
}
if (blk_getlength(s->blk) >=
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
pagesize = 0;
s->mem_oob = 0;
}
} else {
pagesize += 1 << s->page_shift;
}
if (pagesize) {
s->storage = (uint8_t *) memset(g_malloc(s->pages * pagesize),
0xff, s->pages * pagesize);
}
/* Give s->ioaddr a sane value in case we save state before it is used. */
s->ioaddr = s->io;
}
static const Property nand_properties[] = {
DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
DEFINE_PROP_DRIVE("drive", NANDFlashState, blk),
};
static void nand_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = nand_realize;
device_class_set_legacy_reset(dc, nand_reset);
dc->vmsd = &vmstate_nand;
device_class_set_props(dc, nand_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
static const TypeInfo nand_info = {
.name = TYPE_NAND,
.parent = TYPE_DEVICE,
.instance_size = sizeof(NANDFlashState),
.class_init = nand_class_init,
};
static void nand_register_types(void)
{
type_register_static(&nand_info);
}
/*
* Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip
* outputs are R/B and eight I/O pins.
*
* CE, WP and R/B are active low.
*/
void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd)
{
NANDFlashState *s = NAND(dev);
s->cle = cle;
s->ale = ale;
s->ce = ce;
s->wp = wp;
s->gnd = gnd;
if (wp) {
s->status |= NAND_IOSTATUS_UNPROTCT;
} else {
s->status &= ~NAND_IOSTATUS_UNPROTCT;
}
}
void nand_getpins(DeviceState *dev, int *rb)
{
*rb = 1;
}
void nand_setio(DeviceState *dev, uint32_t value)
{
int i;
NANDFlashState *s = NAND(dev);
if (!s->ce && s->cle) {
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
return;
if (value == NAND_CMD_RANDOMREAD1) {
s->addr &= ~((1 << s->addr_shift) - 1);
s->addrlen = 0;
return;
}
}
if (value == NAND_CMD_READ0) {
s->offset = 0;
} else if (value == NAND_CMD_READ1) {
s->offset = 0x100;
value = NAND_CMD_READ0;
} else if (value == NAND_CMD_READ2) {
s->offset = 1 << s->page_shift;
value = NAND_CMD_READ0;
}
s->cmd = value;
if (s->cmd == NAND_CMD_READSTATUS ||
s->cmd == NAND_CMD_PAGEPROGRAM2 ||
s->cmd == NAND_CMD_BLOCKERASE1 ||
s->cmd == NAND_CMD_BLOCKERASE2 ||
s->cmd == NAND_CMD_NOSERIALREAD2 ||
s->cmd == NAND_CMD_RANDOMREAD2 ||
s->cmd == NAND_CMD_RESET) {
nand_command(s);
}
if (s->cmd != NAND_CMD_RANDOMREAD2) {
s->addrlen = 0;
}
}
if (s->ale) {
unsigned int shift = s->addrlen * 8;
uint64_t mask = ~(0xffull << shift);
uint64_t v = (uint64_t)value << shift;
s->addr = (s->addr & mask) | v;
s->addrlen ++;
switch (s->addrlen) {
case 1:
if (s->cmd == NAND_CMD_READID) {
nand_command(s);
}
break;
case 2: /* fix cache address as a byte address */
s->addr <<= (s->buswidth - 1);
break;
case 3:
if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
(s->cmd == NAND_CMD_READ0 ||
s->cmd == NAND_CMD_PAGEPROGRAM1)) {
nand_command(s);
}
break;
case 4:
if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
nand_flash_ids[s->chip_id].size < 256 && /* 1Gb or less */
(s->cmd == NAND_CMD_READ0 ||
s->cmd == NAND_CMD_PAGEPROGRAM1)) {
nand_command(s);
}
break;
case 5:
if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
nand_flash_ids[s->chip_id].size >= 256 && /* 2Gb or more */
(s->cmd == NAND_CMD_READ0 ||
s->cmd == NAND_CMD_PAGEPROGRAM1)) {
nand_command(s);
}
break;
default:
break;
}
}
if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) {
for (i = s->buswidth; i--; value >>= 8) {
s->io[s->iolen ++] = (uint8_t) (value & 0xff);
}
}
} else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
if ((s->addr & ((1 << s->addr_shift) - 1)) <
(1 << s->page_shift) + (1 << s->oob_shift)) {
for (i = s->buswidth; i--; s->addr++, value >>= 8) {
s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
(uint8_t) (value & 0xff);
}
}
}
}
uint32_t nand_getio(DeviceState *dev)
{
int offset;
uint32_t x = 0;
NANDFlashState *s = NAND(dev);
/* Allow sequential reading */
if (!s->iolen && s->cmd == NAND_CMD_READ0) {
offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
s->offset = 0;
s->iolen = nand_load_block(s, offset);
}
if (s->ce || s->iolen <= 0) {
return 0;
}
for (offset = s->buswidth; offset--;) {
x |= s->ioaddr[offset] << (offset << 3);
}
/* after receiving READ STATUS command all subsequent reads will
* return the status register value until another command is issued
*/
if (s->cmd != NAND_CMD_READSTATUS) {
s->addr += s->buswidth;
s->ioaddr += s->buswidth;
s->iolen -= s->buswidth;
}
return x;
}
uint32_t nand_getbuswidth(DeviceState *dev)
{
NANDFlashState *s = (NANDFlashState *) dev;
return s->buswidth << 3;
}
DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id)
{
DeviceState *dev;
if (nand_flash_ids[chip_id].size == 0) {
hw_error("%s: Unsupported NAND chip ID.\n", __func__);
}
dev = qdev_new(TYPE_NAND);
qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
qdev_prop_set_uint8(dev, "chip_id", chip_id);
if (blk) {
qdev_prop_set_drive_err(dev, "drive", blk, &error_fatal);
}
qdev_realize(dev, NULL, &error_fatal);
return dev;
}
type_init(nand_register_types)
#else
/* Program a single page */
static void glue(nand_blk_write_, NAND_PAGE_SIZE)(NANDFlashState *s)
{
uint64_t off, page, sector, soff;
uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
if (PAGE(s->addr) >= s->pages)
return;
if (!s->blk) {
mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
s->offset, s->io, s->iolen);
} else if (s->mem_oob) {
sector = SECTOR(s->addr);
off = (s->addr & PAGE_MASK) + s->offset;
soff = SECTOR_OFFSET(s->addr);
if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS,
PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, NAND_PAGE_SIZE - off));
if (off + s->iolen > NAND_PAGE_SIZE) {
page = PAGE(s->addr);
mem_and(s->storage + (page << OOB_SHIFT), s->io + NAND_PAGE_SIZE - off,
MIN(OOB_SIZE, off + s->iolen - NAND_PAGE_SIZE));
}
if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS,
PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
}
} else {
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
sector = off >> 9;
soff = off & 0x1ff;
if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS,
(PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
mem_and(iobuf + soff, s->io, s->iolen);
if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS,
(PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
}
}
s->offset = 0;
}
/* Erase a single block */
static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s)
{
uint64_t i, page, addr;
uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
if (PAGE(addr) >= s->pages) {
return;
}
if (!s->blk) {
memset(s->storage + PAGE_START(addr),
0xff, (NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift);
} else if (s->mem_oob) {
memset(s->storage + (PAGE(addr) << OOB_SHIFT),
0xff, OOB_SIZE << s->erase_shift);
i = SECTOR(addr);
page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift)));
for (; i < page; i ++)
if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS,
BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
}
} else {
addr = PAGE_START(addr);
page = addr >> 9;
if (blk_pread(s->blk, page << BDRV_SECTOR_BITS,
BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
}
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS,
BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
}
memset(iobuf, 0xff, 0x200);
i = (addr & ~0x1ff) + 0x200;
for (addr += ((NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
i < addr; i += 0x200) {
if (blk_pwrite(s->blk, i, BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n",
__func__, i >> 9);
}
}
page = i >> 9;
if (blk_pread(s->blk, page << BDRV_SECTOR_BITS,
BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
}
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS,
BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
}
}
}
static bool glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
uint64_t addr, unsigned offset)
{
if (PAGE(addr) >= s->pages) {
return false;
}
if (offset > NAND_PAGE_SIZE + OOB_SIZE) {
return false;
}
if (s->blk) {
if (s->mem_oob) {
if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS,
PAGE_SECTORS << BDRV_SECTOR_BITS, s->io, 0) < 0) {
printf("%s: read error in sector %" PRIu64 "\n",
__func__, SECTOR(addr));
}
memcpy(s->io + SECTOR_OFFSET(s->addr) + NAND_PAGE_SIZE,
s->storage + (PAGE(s->addr) << OOB_SHIFT),
OOB_SIZE);
s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
} else {
if (blk_pread(s->blk, PAGE_START(addr),
(PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, s->io, 0)
< 0) {
printf("%s: read error in sector %" PRIu64 "\n",
__func__, PAGE_START(addr) >> 9);
}
s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
}
} else {
memcpy(s->io, s->storage + PAGE_START(s->addr) +
offset, NAND_PAGE_SIZE + OOB_SIZE - offset);
s->ioaddr = s->io;
}
return true;
}
static void glue(nand_init_, NAND_PAGE_SIZE)(NANDFlashState *s)
{
s->oob_shift = PAGE_SHIFT - 5;
s->pages = s->size >> PAGE_SHIFT;
s->addr_shift = ADDR_SHIFT;
s->blk_erase = glue(nand_blk_erase_, NAND_PAGE_SIZE);
s->blk_write = glue(nand_blk_write_, NAND_PAGE_SIZE);
s->blk_load = glue(nand_blk_load_, NAND_PAGE_SIZE);
}
# undef NAND_PAGE_SIZE
# undef PAGE_SHIFT
# undef PAGE_SECTORS
# undef ADDR_SHIFT
#endif /* NAND_IO */

View file

@ -28,7 +28,8 @@
#include "hw/misc/npcm7xx_mft.h" #include "hw/misc/npcm7xx_mft.h"
#include "hw/misc/npcm7xx_pwm.h" #include "hw/misc/npcm7xx_pwm.h"
#include "hw/misc/npcm7xx_rng.h" #include "hw/misc/npcm7xx_rng.h"
#include "hw/net/npcm7xx_emc.h" #include "hw/net/npcm_gmac.h"
#include "hw/net/npcm_pcs.h"
#include "hw/nvram/npcm7xx_otp.h" #include "hw/nvram/npcm7xx_otp.h"
#include "hw/sd/npcm7xx_sdhci.h" #include "hw/sd/npcm7xx_sdhci.h"
#include "hw/timer/npcm7xx_timer.h" #include "hw/timer/npcm7xx_timer.h"
@ -99,6 +100,8 @@ struct NPCM8xxState {
EHCISysBusState ehci[2]; EHCISysBusState ehci[2];
OHCISysBusState ohci[2]; OHCISysBusState ohci[2];
NPCM7xxFIUState fiu[3]; NPCM7xxFIUState fiu[3];
NPCMGMACState gmac[4];
NPCMPCSState pcs;
NPCM7xxSDHCIState mmc; NPCM7xxSDHCIState mmc;
NPCMPSPIState pspi; NPCMPSPIState pspi;
}; };

View file

@ -44,24 +44,6 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base,
uint16_t unlock_addr1, uint16_t unlock_addr1,
int be); int be);
/* nand.c */
DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id);
void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd);
void nand_getpins(DeviceState *dev, int *rb);
void nand_setio(DeviceState *dev, uint32_t value);
uint32_t nand_getio(DeviceState *dev);
uint32_t nand_getbuswidth(DeviceState *dev);
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
#define NAND_MFR_FUJITSU 0x04
#define NAND_MFR_NATIONAL 0x8f
#define NAND_MFR_RENESAS 0x07
#define NAND_MFR_STMICRO 0x20
#define NAND_MFR_HYNIX 0xad
#define NAND_MFR_MICRON 0x2c
/* m25p80.c */ /* m25p80.c */
#define TYPE_M25P80 "m25p80-generic" #define TYPE_M25P80 "m25p80-generic"

View file

@ -30,6 +30,7 @@
#include "qapi/qapi-commands-misc-arm.h" #include "qapi/qapi-commands-misc-arm.h"
#include "qobject/qdict.h" #include "qobject/qdict.h"
#include "qom/qom-qobject.h" #include "qom/qom-qobject.h"
#include "cpu.h"
static GICCapability *gic_cap_new(int version) static GICCapability *gic_cap_new(int version)
{ {

View file

@ -23,6 +23,7 @@
#include "hw/registerfields.h" #include "hw/registerfields.h"
#include "target/arm/kvm-consts.h" #include "target/arm/kvm-consts.h"
#include "cpu.h"
/* /*
* ARMCPRegInfo type field bits: * ARMCPRegInfo type field bits:

View file

@ -22,6 +22,7 @@
#include "hw/registerfields.h" #include "hw/registerfields.h"
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
#include "cpu.h"
/* /*
* Naming convention for isar_feature functions: * Naming convention for isar_feature functions:

20
target/arm/hvf-stub.c Normal file
View file

@ -0,0 +1,20 @@
/*
* QEMU Hypervisor.framework (HVF) stubs for ARM
*
* Copyright (c) Linaro
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "hvf_arm.h"
uint32_t hvf_arm_get_default_ipa_bit_size(void)
{
g_assert_not_reached();
}
uint32_t hvf_arm_get_max_ipa_bit_size(void)
{
g_assert_not_reached();
}

View file

@ -11,7 +11,7 @@
#ifndef QEMU_HVF_ARM_H #ifndef QEMU_HVF_ARM_H
#define QEMU_HVF_ARM_H #define QEMU_HVF_ARM_H
#include "cpu.h" #include "target/arm/cpu-qom.h"
/** /**
* hvf_arm_init_debug() - initialize guest debug capabilities * hvf_arm_init_debug() - initialize guest debug capabilities
@ -22,23 +22,7 @@ void hvf_arm_init_debug(void);
void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu); void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu);
#ifdef CONFIG_HVF
uint32_t hvf_arm_get_default_ipa_bit_size(void); uint32_t hvf_arm_get_default_ipa_bit_size(void);
uint32_t hvf_arm_get_max_ipa_bit_size(void); uint32_t hvf_arm_get_max_ipa_bit_size(void);
#else
static inline uint32_t hvf_arm_get_default_ipa_bit_size(void)
{
return 0;
}
static inline uint32_t hvf_arm_get_max_ipa_bit_size(void)
{
return 0;
}
#endif
#endif #endif

View file

@ -12,6 +12,7 @@
#define QEMU_KVM_ARM_H #define QEMU_KVM_ARM_H
#include "system/kvm.h" #include "system/kvm.h"
#include "target/arm/cpu-qom.h"
#define KVM_ARM_VGIC_V2 (1 << 0) #define KVM_ARM_VGIC_V2 (1 << 0)
#define KVM_ARM_VGIC_V3 (1 << 1) #define KVM_ARM_VGIC_V3 (1 << 1)

View file

@ -3,7 +3,6 @@ arm_common_ss = ss.source_set()
arm_ss.add(files( arm_ss.add(files(
'gdbstub.c', 'gdbstub.c',
)) ))
arm_ss.add(zlib)
arm_ss.add(when: 'TARGET_AARCH64', if_true: files( arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
'cpu64.c', 'cpu64.c',
@ -32,6 +31,7 @@ arm_common_system_ss.add(files('cpu.c'))
arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files(
'cpu32-stubs.c')) 'cpu32-stubs.c'))
arm_common_system_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) arm_common_system_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
arm_common_system_ss.add(when: 'CONFIG_HVF', if_false: files('hvf-stub.c'))
arm_common_system_ss.add(files( arm_common_system_ss.add(files(
'arch_dump.c', 'arch_dump.c',
'arm-powerctl.c', 'arm-powerctl.c',
@ -48,7 +48,7 @@ subdir('hvf')
if 'CONFIG_TCG' in config_all_accel if 'CONFIG_TCG' in config_all_accel
subdir('tcg') subdir('tcg')
else else
arm_ss.add(files('tcg-stubs.c')) arm_common_system_ss.add(files('tcg-stubs.c'))
endif endif
target_arch += {'arm': arm_ss} target_arch += {'arm': arm_ss}

View file

@ -56,6 +56,8 @@ arm_system_ss.add(files(
arm_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c')) arm_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c'))
arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files('cpu-v7m.c')) arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files('cpu-v7m.c'))
arm_common_ss.add(zlib)
arm_common_ss.add(files( arm_common_ss.add(files(
'arith_helper.c', 'arith_helper.c',
'crypto_helper.c', 'crypto_helper.c',

View file

@ -137,6 +137,7 @@ tests_arm_system_thorough = [
'arm_raspi2', 'arm_raspi2',
'arm_replay', 'arm_replay',
'arm_smdkc210', 'arm_smdkc210',
'arm_stellaris',
'arm_sx1', 'arm_sx1',
'arm_vexpress', 'arm_vexpress',
'arm_virt', 'arm_virt',

View file

@ -0,0 +1,48 @@
#!/usr/bin/env python3
#
# Functional test that checks the serial console of the stellaris machines
#
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern
from qemu_test import wait_for_console_pattern
class StellarisMachine(QemuSystemTest):
ASSET_DAY22 = Asset(
'https://www.qemu-advent-calendar.org/2023/download/day22.tar.gz',
'ae3a63ef4b7a22c21bfc7fc0d85e402fe95e223308ed23ac854405016431ff51')
def test_lm3s6965evb(self):
self.set_machine('lm3s6965evb')
kernel_path = self.archive_extract(self.ASSET_DAY22,
member='day22/day22.bin')
self.vm.set_console()
self.vm.add_args('-kernel', kernel_path)
self.vm.launch()
wait_for_console_pattern(self, 'In a one horse open')
ASSET_NOTMAIN = Asset(
'https://github.com/Ahelion/QemuArmM4FDemoSw/raw/master/build/notmain.bin',
'6ceda031aa081a420fca2fca9e137fa681d6e3820d820ad1917736cb265e611a')
def test_lm3s811evb(self):
self.set_machine('lm3s811evb')
kernel_path = self.ASSET_NOTMAIN.fetch()
self.vm.set_console()
self.vm.add_args('-cpu', 'cortex-m4')
self.vm.add_args('-kernel', kernel_path)
self.vm.launch()
# The test kernel emits an initial '!' and then waits for input.
# For each character that we send it responds with a certain
# other ASCII character.
wait_for_console_pattern(self, '!')
exec_command_and_wait_for_pattern(self, '789', 'cdf')
if __name__ == '__main__':
QemuSystemTest.main()

View file

@ -208,9 +208,10 @@ qtests_npcm7xx = \
'npcm7xx_sdhci-test', 'npcm7xx_sdhci-test',
'npcm7xx_smbus-test', 'npcm7xx_smbus-test',
'npcm7xx_timer-test', 'npcm7xx_timer-test',
'npcm7xx_watchdog_timer-test', 'npcm7xx_watchdog_timer-test'] + \
'npcm_gmac-test'] + \
(slirp.found() ? ['npcm7xx_emc-test'] : []) (slirp.found() ? ['npcm7xx_emc-test'] : [])
qtests_npcm8xx = \
['npcm_gmac-test']
qtests_aspeed = \ qtests_aspeed = \
['aspeed_gpio-test', ['aspeed_gpio-test',
'aspeed_hace-test', 'aspeed_hace-test',
@ -259,6 +260,7 @@ qtests_aarch64 = \
(config_all_accel.has_key('CONFIG_TCG') and \ (config_all_accel.has_key('CONFIG_TCG') and \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \ config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
(config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \ (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
(config_all_devices.has_key('CONFIG_NPCM8XX') ? qtests_npcm8xx : []) + \
['arm-cpu-features', ['arm-cpu-features',
'numa-test', 'numa-test',
'boot-serial-test', 'boot-serial-test',

View file

@ -36,7 +36,7 @@ typedef struct TestData {
const GMACModule *module; const GMACModule *module;
} TestData; } TestData;
/* Values extracted from hw/arm/npcm7xx.c */ /* Values extracted from hw/arm/npcm8xx.c */
static const GMACModule gmac_module_list[] = { static const GMACModule gmac_module_list[] = {
{ {
.irq = 14, .irq = 14,
@ -46,6 +46,14 @@ static const GMACModule gmac_module_list[] = {
.irq = 15, .irq = 15,
.base_addr = 0xf0804000 .base_addr = 0xf0804000
}, },
{
.irq = 16,
.base_addr = 0xf0806000
},
{
.irq = 17,
.base_addr = 0xf0808000
}
}; };
/* Returns the index of the GMAC module. */ /* Returns the index of the GMAC module. */
@ -174,18 +182,32 @@ static uint32_t gmac_read(QTestState *qts, const GMACModule *mod,
return qtest_readl(qts, mod->base_addr + regno); return qtest_readl(qts, mod->base_addr + regno);
} }
static uint16_t pcs_read(QTestState *qts, const GMACModule *mod,
NPCMRegister regno)
{
uint32_t write_value = (regno & 0x3ffe00) >> 9;
qtest_writel(qts, PCS_BASE_ADDRESS + NPCM_PCS_IND_AC_BA, write_value);
uint32_t read_offset = regno & 0x1ff;
return qtest_readl(qts, PCS_BASE_ADDRESS + read_offset);
}
/* Check that GMAC registers are reset to default value */ /* Check that GMAC registers are reset to default value */
static void test_init(gconstpointer test_data) static void test_init(gconstpointer test_data)
{ {
const TestData *td = test_data; const TestData *td = test_data;
const GMACModule *mod = td->module; const GMACModule *mod = td->module;
QTestState *qts = qtest_init("-machine npcm750-evb"); QTestState *qts = qtest_init("-machine npcm845-evb");
#define CHECK_REG32(regno, value) \ #define CHECK_REG32(regno, value) \
do { \ do { \
g_assert_cmphex(gmac_read(qts, mod, (regno)), ==, (value)); \ g_assert_cmphex(gmac_read(qts, mod, (regno)), ==, (value)); \
} while (0) } while (0)
#define CHECK_REG_PCS(regno, value) \
do { \
g_assert_cmphex(pcs_read(qts, mod, (regno)), ==, (value)); \
} while (0)
CHECK_REG32(NPCM_DMA_BUS_MODE, 0x00020100); CHECK_REG32(NPCM_DMA_BUS_MODE, 0x00020100);
CHECK_REG32(NPCM_DMA_XMT_POLL_DEMAND, 0); CHECK_REG32(NPCM_DMA_XMT_POLL_DEMAND, 0);
CHECK_REG32(NPCM_DMA_RCV_POLL_DEMAND, 0); CHECK_REG32(NPCM_DMA_RCV_POLL_DEMAND, 0);
@ -235,6 +257,63 @@ static void test_init(gconstpointer test_data)
CHECK_REG32(NPCM_GMAC_PTP_TAR, 0); CHECK_REG32(NPCM_GMAC_PTP_TAR, 0);
CHECK_REG32(NPCM_GMAC_PTP_TTSR, 0); CHECK_REG32(NPCM_GMAC_PTP_TTSR, 0);
if (mod->base_addr == 0xf0802000) {
CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID1, 0x699e);
CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID2, 0);
CHECK_REG_PCS(NPCM_PCS_SR_CTL_STS, 0x8000);
CHECK_REG_PCS(NPCM_PCS_SR_MII_CTRL, 0x1140);
CHECK_REG_PCS(NPCM_PCS_SR_MII_STS, 0x0109);
CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID1, 0x699e);
CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID2, 0x0ced0);
CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_ADV, 0x0020);
CHECK_REG_PCS(NPCM_PCS_SR_MII_LP_BABL, 0);
CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_EXPN, 0);
CHECK_REG_PCS(NPCM_PCS_SR_MII_EXT_STS, 0xc000);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_ABL, 0x0003);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR, 0x0038);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_UPR, 0);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR, 0x0038);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_UPR, 0);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR, 0x0058);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_UPR, 0);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR, 0x0048);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_UPR, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MMD_DIG_CTRL1, 0x2400);
CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_CTRL, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_INTR_STS, 0x000a);
CHECK_REG_PCS(NPCM_PCS_VR_MII_TC, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_DBG_CTRL, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL0, 0x899c);
CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_TXTIMER, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_RXTIMER, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_LINK_TIMER_CTRL, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL1, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_STS, 0x0010);
CHECK_REG_PCS(NPCM_PCS_VR_MII_ICG_ERRCNT1, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MISC_STS, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_RX_LSTS, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_BSTCTRL0, 0x00a);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_LVLCTRL0, 0x007f);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL0, 0x0001);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL1, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_STS, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL0, 0x0100);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL1, 0x1100);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0, 0x000e);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL0, 0x0100);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL1, 0x0032);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_STS, 0x0001);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL2, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_LVL_CTRL, 0x0019);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL0, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL1, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_CTRL2, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_ERRCNT_SEL, 0);
}
qtest_quit(qts); qtest_quit(qts);
} }
@ -242,7 +321,7 @@ static void gmac_add_test(const char *name, const TestData* td,
GTestDataFunc fn) GTestDataFunc fn)
{ {
g_autofree char *full_name = g_strdup_printf( g_autofree char *full_name = g_strdup_printf(
"npcm7xx_gmac/gmac[%d]/%s", gmac_module_index(td->module), name); "npcm8xx_gmac/gmac[%d]/%s", gmac_module_index(td->module), name);
qtest_add_data_func(full_name, td, fn); qtest_add_data_func(full_name, td, fn);
} }