Compare commits
150
Commits
v0.12.2
...
stable-0.12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6394bd0e05 | ||
|
|
fa719811ac | ||
|
|
174f225e9d | ||
|
|
e916448940 | ||
|
|
bb44e0bbce | ||
|
|
191d44fc43 | ||
|
|
a2f0cbaa58 | ||
|
|
a9d9a66f13 | ||
|
|
37060c28e5 | ||
|
|
7205c21e76 | ||
|
|
ceef722d01 | ||
|
|
dfe0bb55ee | ||
|
|
6fd82592ce | ||
|
|
39187b5192 | ||
|
|
729862401d | ||
|
|
34d0d68bdf | ||
|
|
82e9cbeb0d | ||
|
|
2020dd5535 | ||
|
|
0c0f53e25c | ||
|
|
3dbe0714dd | ||
|
|
9067bac11d | ||
|
|
74471f3742 | ||
|
|
370f80376a | ||
|
|
ed3aac289a | ||
|
|
11b52a6536 | ||
|
|
b6185fc79c | ||
|
|
8fd7d5438e | ||
|
|
a513171f80 | ||
|
|
ff9e177617 | ||
|
|
db3519a9ec | ||
|
|
258e351d12 | ||
|
|
cd14f4d346 | ||
|
|
df631629b1 | ||
|
|
af0269b036 | ||
|
|
d37dbf988d | ||
|
|
cc7ed88f28 | ||
|
|
07442ab4a1 | ||
|
|
dbe6a18d82 | ||
|
|
7dd007c2ed | ||
|
|
9c6a8f503d | ||
|
|
0c459361a1 | ||
|
|
72d3457e8d | ||
|
|
e1f0c1d05d | ||
|
|
74bcc51b99 | ||
|
|
7e4f956056 | ||
|
|
1fb9798b69 | ||
|
|
9f6a84bc43 | ||
|
|
8cef921d18 | ||
|
|
b04c3db504 | ||
|
|
d04d7cf158 | ||
|
|
2b8bdd5c7f | ||
|
|
2a44494726 | ||
|
|
8f30db54d9 | ||
|
|
b09ac1abe7 | ||
|
|
012d4869c1 | ||
|
|
3597c9c1d5 | ||
|
|
3b4bef0696 | ||
|
|
d899303743 | ||
|
|
5773685183 | ||
|
|
d40ba77ebf | ||
|
|
a8c46d182c | ||
|
|
d80e20a1c3 | ||
|
|
1ce4fad939 | ||
|
|
9167a242db | ||
|
|
09e96924ec | ||
|
|
69ff4e9dbd | ||
|
|
0434349d6a | ||
|
|
e007221223 | ||
|
|
4622317288 | ||
|
|
ffac613ff9 | ||
|
|
aba5288247 | ||
|
|
4f7cb96931 | ||
|
|
fafc2e4b33 | ||
|
|
83ef70f24a | ||
|
|
de17c16e1f | ||
|
|
9462695b64 | ||
|
|
5eb089588e | ||
|
|
2039f70c23 | ||
|
|
082a9fc256 | ||
|
|
36a013c956 | ||
|
|
c4c4b32b81 | ||
|
|
804b6ab08d | ||
|
|
81b168a702 | ||
|
|
5c6892078a | ||
|
|
18a21890ff | ||
|
|
6629fa6473 | ||
|
|
2a7996ce0e | ||
|
|
8ec131fb59 | ||
|
|
30d061750d | ||
|
|
c5f5dc5bad | ||
|
|
d2df336c58 | ||
|
|
b299b12b17 | ||
|
|
c248df6161 | ||
|
|
7d5625d5f7 | ||
|
|
cc21d131e3 | ||
|
|
41a5bda61f | ||
|
|
5163f6e864 | ||
|
|
6173d56bdc | ||
|
|
f39942d217 | ||
|
|
5dde87088f | ||
|
|
3fa017e24b | ||
|
|
35924dbe8c | ||
|
|
88aa905668 | ||
|
|
b93c5c84c8 | ||
|
|
f203baee5b | ||
|
|
5e3be62385 | ||
|
|
b391493bc6 | ||
|
|
57f9f4c9f5 | ||
|
|
7ebc79037c | ||
|
|
ea299062eb | ||
|
|
e03dd1a6c2 | ||
|
|
535d2eb34a | ||
|
|
beb8eab90c | ||
|
|
8d67694fbf | ||
|
|
02510b2436 | ||
|
|
b57a2297f2 | ||
|
|
43fab08210 | ||
|
|
915080e6b1 | ||
|
|
9f59ddcc4f | ||
|
|
999ceb2c1d | ||
|
|
307331a42a | ||
|
|
6728dd464b | ||
|
|
bb45bcc8de | ||
|
|
096109c804 | ||
|
|
7ae1fcc88c | ||
|
|
299e0bc52a | ||
|
|
74f0529e24 | ||
|
|
614971158c | ||
|
|
afa328b1b2 | ||
|
|
868dab5dc2 | ||
|
|
29bb3bf350 | ||
|
|
dbf45b44b7 | ||
|
|
d0d888bc6d | ||
|
|
19abbad0da | ||
|
|
f48aba6de7 | ||
|
|
cb2ae96bf6 | ||
|
|
848f874ca1 | ||
|
|
a1a86bf902 | ||
|
|
c727a05459 | ||
|
|
eb05143e24 | ||
|
|
0c709e6195 | ||
|
|
dc88aa49b4 | ||
|
|
dc2ffbf6d8 | ||
|
|
d3bf9367f2 | ||
|
|
c502715a74 | ||
|
|
b9a61d2154 | ||
|
|
9525204c5d | ||
|
|
f79d556b4f | ||
|
|
41ae9ece21 | ||
|
|
40480d2bf4 |
No files matched your search
@@ -1,3 +1,152 @@
|
||||
version 0.12.5
|
||||
- audio/alsa: Handle SND_PCM_STATE_SETUP in alsa_poll_handler
|
||||
- block: Handle multiwrite errors only when all requests have completed
|
||||
- block: Fix early failure in multiwrite
|
||||
- vpc: Use bdrv_(p)write_sync for metadata writes
|
||||
- vmdk: Use bdrv_(p)write_sync for metadata writes
|
||||
- qcow2: Use bdrv_(p)write_sync for metadata writes
|
||||
- qcow: Use bdrv_(p)write_sync for metadata writes
|
||||
- block: Add bdrv_(p)write_sync
|
||||
- qcow2: Restore L1 entry on l2_allocate failure
|
||||
- block/vdi: Fix image opening and creation for odd disk sizes
|
||||
- block/vpc: Fix conversion from size to disk geometry
|
||||
- qcow2: Remove abort on free_clusters failure
|
||||
- vmdk: Fix COW
|
||||
- qcow2: Fix creation of large images
|
||||
- vmdk: fix double free
|
||||
- qemu-options: add documentation for stdio signal=on|off
|
||||
- target-arm : fix parallel saturated subtraction implementation
|
||||
- target-arm : fix thumb2 parallel add/sub opcode decoding
|
||||
- target-arm: fix addsub/subadd implementation
|
||||
- target-i386: fix xchg rax,r8
|
||||
- block/vvfat.c: fix warnings with _FORTIFY_SOURCE
|
||||
- audio/alsa: Spelling typo (paramters)
|
||||
- target-mips: fix DINSU instruction
|
||||
- Correct definitions for FD_CMD_SAVE and FD_CMD_RESTORE
|
||||
- qcow2: Fix corruption after error in update_refcount
|
||||
- qcow2: Fix corruption after refblock allocation
|
||||
- block: Fix multiwrite with overlapping requests
|
||||
- qcow2: Fix error handling in l2_allocate
|
||||
- qcow2: Clear L2 table cache after write error
|
||||
- ide: Fix ide_dma_cancel
|
||||
- usb-bus: fix no params
|
||||
- Avoid crash on '-usbdevice <device>' without parameters
|
||||
- Fix -usbdevice crash
|
||||
- Fix multiboot compilation
|
||||
- Fix missing symbols in .rel/.rela.plt sections
|
||||
- target-ppc: fix RFI by clearing some bits of MSR
|
||||
- Fix typo in balloon help
|
||||
- arm_timer: fix oneshot mode
|
||||
- arm_timer: reload timer when enabled
|
||||
- qemu-sockets: avoid strlen of NULL pointer
|
||||
- block: fix aio_flush segfaults for read-only protocols (e.g. curl)
|
||||
- virtio-blk: fix barrier support
|
||||
- block: fix sector comparism in multiwrite_req_compare
|
||||
- pci: irq_state vmstate breakage
|
||||
- qemu-img: use the heap instead of the huge stack array for win32
|
||||
|
||||
version 0.12.4
|
||||
- Workaround for broken OSS_GETVERSION on FreeBSD, part two (Juergen Lock)
|
||||
- oss: fix fragment setting (malc)
|
||||
- oss: issue OSS_GETVERSION ioctl only when needed (malc)
|
||||
- oss: refactor code around policy setting (malc)
|
||||
- oss: workaround for cases when OSS_GETVERSION is not defined (malc)
|
||||
- block: Free iovec arrays allocated by multiwrite_merge() (Stefan Hajnoczi)
|
||||
- lsi: fix segfault in lsi_command_complete (Gerd Hoffmann)
|
||||
- lsi: pass lsi_request to lsi_reselect (Gerd Hoffmann)
|
||||
- lsi: move dma_len+dma_buf into lsi_request (Gerd Hoffmann)
|
||||
- lsi: move current_dev into lsi_request (Gerd Hoffmann)
|
||||
- lsi: have lsi_request for the whole life time of the request. (Gerd Hoffmann)
|
||||
- lsi: use QTAILQ for lsi_queue (Gerd Hoffmann)
|
||||
- tcp/mips: Change TCG_AREG0 (fp -> s0) (Stefan Weil)
|
||||
- sh_pci: fix memory and I/O access (Aurelien Jarno)
|
||||
- Fix incoming migration with iothread (Marcelo Tosatti)
|
||||
- Fix SIGFPE for vnc display of width/height = 1 (Chris Webb)
|
||||
- net: remove broken net_set_boot_mask() boot device validation (Eduardo Habkost)
|
||||
- qcow2: Remove request from in-flight list after error (Kevin Wolf)
|
||||
- qcow2: Don't ignore immediate read/write failures (Kevin Wolf)
|
||||
- block: Fix multiwrite memory leak in error case (Kevin Wolf)
|
||||
- block: Fix error code in multiwrite for immediate failures (Kevin Wolf)
|
||||
- block: Fix multiwrite error handling (Kevin Wolf)
|
||||
- scsi-disk: fix buffer overflow (Gerd Hoffmann)
|
||||
- qcow2: Rewrite alloc_refcount_block/grow_refcount_table (Kevin Wolf)
|
||||
- qcow2: Factor next_refcount_table_size out (Kevin Wolf)
|
||||
- block: avoid creating too large iovecs in multiwrite_merge (Christoph Hellwig)
|
||||
- json-parser: Fix segfault on malformed input (Kevin Wolf)
|
||||
- linux-user: switch default ppc64 CPU to 970fx from 970 (Aurelien Jarno)
|
||||
- target-sh4: MMU: fix store queue addresses (Aurelien Jarno)
|
||||
- target-sh4: MMU: fix ITLB priviledge check (Aurelien Jarno)
|
||||
- target-sh4: MMU: fix mem_idx computation (Aurelien Jarno)
|
||||
- sh7750: handle MMUCR TI bit (Aurelien Jarno)
|
||||
- UHCI spurious interrut fix (Paul Brook)
|
||||
- tcg/mips: fix branch offset during retranslation (Aurelien Jarno)
|
||||
- tcg/arm: correctly save/restore registers in prologue/epilogue (Aurelien Jarno)
|
||||
- workaround for cmd646 bmdma register access while no dma is active (Igor V. Kovalenko)
|
||||
- Fix corner case in chardev udp: parameter (Jan Kiszka)
|
||||
- Don't set default monitor when there is a mux'ed one (Jan Kiszka)
|
||||
- spelling typo (compatibilty) in hw/fw_cfg.c (Vagrant Cascadian)
|
||||
- fdc: fix drive property handling. (Gerd Hoffmann)
|
||||
- target-i386: fix commit c22549204a6edc431e8e4358e61bd56386ff6957 (TeLeMan)
|
||||
- target-i386: fix SIB decoding with index = 4 (Aurelien Jarno)
|
||||
- Fix segfault with ram_size > 4095M without kvm (Ryan Harper)
|
||||
- target-i386: Fix long jumps/calls in long mode with REX.W set (malc)
|
||||
- target-i386: fix lddqu SSE instruction (Aurelien Jarno)
|
||||
- qemu-char.c: drop debug printfs from qemu_chr_parse_compat (Jan Kiszka)
|
||||
- fix undefined shifts by >32 (Paolo Bonzini)
|
||||
- Fix qemu -net user,hostfwd= example (Aurelien Jarno)
|
||||
|
||||
version 0.12.3
|
||||
- kvm: Fix eflags corruption in kvm mode (Jan Kiszka)
|
||||
- qcow2: Fix access after end of array (Kevin Wolf)
|
||||
- ide save/restore pio/atapi cmd transfer fields and io buffer (Marcelo Tosatti)
|
||||
- net: Monitor command set_link finds only VLAN clients, fix (Markus Armbruster)
|
||||
- net: info network shows only VLAN clients, fix (Markus Armbruster)
|
||||
- net: net_check_clients() checks only VLAN clients, fix (Markus Armbruster)
|
||||
- net: Fix bogus "Warning: vlan 0 with no nics" with -device (Markus Armbruster)
|
||||
- net: net_check_clients() runs too early to see -device, fix (Markus Armbruster)
|
||||
- net: Remove unused net_client_uninit() (Markus Armbruster)
|
||||
- don't dereference NULL after failed strdup (Jim Meyering)
|
||||
- virtio-net: fix network stall under load (Tom Lendacky)
|
||||
- json: fix PRId64 on Win32 (Roy Tam)
|
||||
- fix inet_parse typo (Marcelo Tosatti)
|
||||
- iothread: fix vcpu stop with smp tcg (Marcelo Tosatti)
|
||||
- segfault due to buffer overrun in usb-serial (David S. Ahern)
|
||||
- qcow2: Fix signedness bugs (Kevin Wolf)
|
||||
- Do not ignore error, if open file failed (-serial /dev/tty) (Evgeniy Dushistov)
|
||||
- pc-bios: update to newer version of (stable) seabios (Anthony Liguori)
|
||||
- target-mips: fix ROTR and DROTR by zero (Aurelien Jarno)
|
||||
- target-mips: fix CpU exception for coprocessor 0 (Nathan Froyd)
|
||||
- tcg/mips: fix crash in tcg_out_qemu_ld() (Aurelien Jarno)
|
||||
- target-mips: don't call cpu_loop_exit() from helper.c (Aurelien Jarno)
|
||||
- virtio-blk: Fix error cases which ignored rerror/werror (Kevin Wolf)
|
||||
- virtio-blk: Fix restart after read error (Kevin Wolf)
|
||||
- virtio_blk: Factor virtio_blk_handle_request out (Kevin Wolf)
|
||||
- cirrus: Properly re-register cirrus_linear_io_addr on vram unmap (Jan Kiszka)
|
||||
- qcow2: Don't ignore qcow2_alloc_clusters return value (Kevin Wolf)
|
||||
- qcow2: Don't ignore update_refcount return value (Kevin Wolf)
|
||||
- qcow2: Allow updating no refcounts (Kevin Wolf)
|
||||
- qcow2: Improve error handling in update_refcount (Kevin Wolf)
|
||||
- qcow2: Fix error handling in grow_refcount_table (Kevin Wolf)
|
||||
- block: Return original error codes in bdrv_pread/write (Kevin Wolf)
|
||||
- qcow2: Return 0/-errno in qcow2_alloc_cluster_offset (Kevin Wolf)
|
||||
- qcow2: Return 0/-errno in get_cluster_table (Kevin Wolf)
|
||||
- qcow2: Fix error handling in qcow_save_vmstate (Kevin Wolf)
|
||||
- qcow2: Fix error handling in qcow2_grow_l1_table (Kevin Wolf)
|
||||
- win32/sdl: Fix toggle full screen (Herve Poussineau)
|
||||
- win32: pair qemu_memalign() with qemu_vfree() (Herve Poussineau)
|
||||
- vnc_refresh: calling vnc_update_client might free vs (Stefano Stabellini)
|
||||
- Musicpal: Fix descriptor walk in eth_send (Jan Kiszka)
|
||||
- Musicpal: Fix wm8750 I2C address (Jan Kiszka)
|
||||
- fix savevm command without id or tag (Marcelo Tosatti)
|
||||
- reduce number of reinjects on ACK (Gleb Natapov)
|
||||
- QMP: Fix asynchronous events delivery (Luiz Capitulino)
|
||||
- Documentation: Add missing documentation for qdev related command line options (Stefan Weil)
|
||||
- pc: add driver version compat properties (Gerd Hoffmann)
|
||||
- scsi: device version property (Gerd Hoffmann)
|
||||
- ide: device version property (Gerd Hoffmann)
|
||||
- QMP: Emit asynchronous events on all QMP monitors (Adam Litke)
|
||||
- Fix QEMU_WARN_UNUSED_RESULT (Kevin Wolf)
|
||||
|
||||
version 0.12.2:
|
||||
- Qemu's internal TFTP server breaks lock-step-iness of TFTP (Milan Plzik)
|
||||
- osdep.c: Fix accept4 fallback (Kevin Wolf)
|
||||
|
||||
@@ -113,7 +113,9 @@ void qemu_aio_flush(void)
|
||||
qemu_aio_wait();
|
||||
|
||||
QLIST_FOREACH(node, &aio_handlers, node) {
|
||||
ret |= node->io_flush(node->opaque);
|
||||
if (node->io_flush) {
|
||||
ret |= node->io_flush(node->opaque);
|
||||
}
|
||||
}
|
||||
} while (qemu_bh_poll() || ret > 0);
|
||||
}
|
||||
|
||||
+5
-1
@@ -213,6 +213,10 @@ static void alsa_poll_handler (void *opaque)
|
||||
|
||||
state = snd_pcm_state (hlp->handle);
|
||||
switch (state) {
|
||||
case SND_PCM_STATE_SETUP:
|
||||
alsa_recover (hlp->handle);
|
||||
break;
|
||||
|
||||
case SND_PCM_STATE_XRUN:
|
||||
alsa_recover (hlp->handle);
|
||||
break;
|
||||
@@ -665,7 +669,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
|
||||
(obt->fmt != req->fmt ||
|
||||
obt->nchannels != req->nchannels ||
|
||||
obt->freq != req->freq)) {
|
||||
dolog ("Audio paramters for %s\n", typ);
|
||||
dolog ("Audio parameters for %s\n", typ);
|
||||
alsa_dump_info (req, obt);
|
||||
}
|
||||
|
||||
|
||||
+50
-18
@@ -38,6 +38,10 @@
|
||||
#define AUDIO_CAP "oss"
|
||||
#include "audio_int.h"
|
||||
|
||||
#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
|
||||
#define USE_DSP_POLICY
|
||||
#endif
|
||||
|
||||
typedef struct OSSVoiceOut {
|
||||
HWVoiceOut hw;
|
||||
void *pcm_buf;
|
||||
@@ -236,14 +240,39 @@ static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_DSP_POLICY
|
||||
static int oss_get_version (int fd, int *version, const char *typ)
|
||||
{
|
||||
if (ioctl (fd, OSS_GETVERSION, &version)) {
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
/*
|
||||
* Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
|
||||
* since 7.x, but currently only on the mixer device (or in
|
||||
* the Linuxolator), and in the native version that part of
|
||||
* the code is in fact never reached so the ioctl fails anyway.
|
||||
* Until this is fixed, just check the errno and if its what
|
||||
* FreeBSD's sound drivers return atm assume they are new enough.
|
||||
*/
|
||||
if (errno == EINVAL) {
|
||||
*version = 0x040000;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
oss_logerr2 (errno, typ, "Failed to get OSS version\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int oss_open (int in, struct oss_params *req,
|
||||
struct oss_params *obt, int *pfd)
|
||||
{
|
||||
int fd;
|
||||
int version;
|
||||
int oflags = conf.exclusive ? O_EXCL : 0;
|
||||
audio_buf_info abinfo;
|
||||
int fmt, freq, nchannels;
|
||||
int setfragment = 1;
|
||||
const char *dspname = in ? conf.devpath_in : conf.devpath_out;
|
||||
const char *typ = in ? "ADC" : "DAC";
|
||||
|
||||
@@ -281,27 +310,30 @@ static int oss_open (int in, struct oss_params *req,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ioctl (fd, OSS_GETVERSION, &version)) {
|
||||
oss_logerr2 (errno, typ, "Failed to get OSS version\n");
|
||||
version = 0;
|
||||
}
|
||||
#ifdef USE_DSP_POLICY
|
||||
if (conf.policy >= 0) {
|
||||
int version;
|
||||
|
||||
if (conf.debug) {
|
||||
dolog ("OSS version = %#x\n", version);
|
||||
}
|
||||
if (!oss_get_version (fd, &version, typ)) {
|
||||
if (conf.debug) {
|
||||
dolog ("OSS version = %#x\n", version);
|
||||
}
|
||||
|
||||
#ifdef SNDCTL_DSP_POLICY
|
||||
if (conf.policy >= 0 && version >= 0x040000) {
|
||||
int policy = conf.policy;
|
||||
if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
|
||||
oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n",
|
||||
conf.policy);
|
||||
goto err;
|
||||
if (version >= 0x040000) {
|
||||
int policy = conf.policy;
|
||||
if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
|
||||
oss_logerr2 (errno, typ,
|
||||
"Failed to set timing policy to %d\n",
|
||||
conf.policy);
|
||||
goto err;
|
||||
}
|
||||
setfragment = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
|
||||
if (setfragment) {
|
||||
int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
|
||||
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
|
||||
oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
|
||||
@@ -857,7 +889,7 @@ static struct audio_option oss_options[] = {
|
||||
.valp = &conf.exclusive,
|
||||
.descr = "Open device in exclusive mode (vmix wont work)"
|
||||
},
|
||||
#ifdef SNDCTL_DSP_POLICY
|
||||
#ifdef USE_DSP_POLICY
|
||||
{
|
||||
.name = "POLICY",
|
||||
.tag = AUD_OPT_INT,
|
||||
|
||||
@@ -452,6 +452,8 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
|
||||
(flags & (BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO));
|
||||
else
|
||||
open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
|
||||
|
||||
bs->open_flags = open_flags;
|
||||
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv))
|
||||
ret = -ENOTSUP;
|
||||
else
|
||||
@@ -691,6 +693,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
|
||||
int len, nb_sectors, count;
|
||||
int64_t sector_num;
|
||||
int ret;
|
||||
|
||||
count = count1;
|
||||
/* first read to align to sector start */
|
||||
@@ -699,8 +702,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||
len = count;
|
||||
sector_num = offset >> BDRV_SECTOR_BITS;
|
||||
if (len > 0) {
|
||||
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
|
||||
return -EIO;
|
||||
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
|
||||
return ret;
|
||||
memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len);
|
||||
count -= len;
|
||||
if (count == 0)
|
||||
@@ -712,8 +715,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||
/* read the sectors "in place" */
|
||||
nb_sectors = count >> BDRV_SECTOR_BITS;
|
||||
if (nb_sectors > 0) {
|
||||
if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
|
||||
return -EIO;
|
||||
if ((ret = bdrv_read(bs, sector_num, buf, nb_sectors)) < 0)
|
||||
return ret;
|
||||
sector_num += nb_sectors;
|
||||
len = nb_sectors << BDRV_SECTOR_BITS;
|
||||
buf += len;
|
||||
@@ -722,8 +725,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||
|
||||
/* add data from the last sector */
|
||||
if (count > 0) {
|
||||
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
|
||||
return -EIO;
|
||||
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
|
||||
return ret;
|
||||
memcpy(buf, tmp_buf, count);
|
||||
}
|
||||
return count1;
|
||||
@@ -735,6 +738,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
|
||||
int len, nb_sectors, count;
|
||||
int64_t sector_num;
|
||||
int ret;
|
||||
|
||||
count = count1;
|
||||
/* first write to align to sector start */
|
||||
@@ -743,11 +747,11 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
len = count;
|
||||
sector_num = offset >> BDRV_SECTOR_BITS;
|
||||
if (len > 0) {
|
||||
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
|
||||
return -EIO;
|
||||
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
|
||||
return ret;
|
||||
memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
|
||||
if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
|
||||
return -EIO;
|
||||
if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
|
||||
return ret;
|
||||
count -= len;
|
||||
if (count == 0)
|
||||
return count1;
|
||||
@@ -758,8 +762,8 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
/* write the sectors "in place" */
|
||||
nb_sectors = count >> BDRV_SECTOR_BITS;
|
||||
if (nb_sectors > 0) {
|
||||
if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
|
||||
return -EIO;
|
||||
if ((ret = bdrv_write(bs, sector_num, buf, nb_sectors)) < 0)
|
||||
return ret;
|
||||
sector_num += nb_sectors;
|
||||
len = nb_sectors << BDRV_SECTOR_BITS;
|
||||
buf += len;
|
||||
@@ -768,15 +772,52 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
|
||||
/* add data from the last sector */
|
||||
if (count > 0) {
|
||||
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
|
||||
return -EIO;
|
||||
if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
|
||||
return ret;
|
||||
memcpy(tmp_buf, buf, count);
|
||||
if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
|
||||
return -EIO;
|
||||
if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
|
||||
return ret;
|
||||
}
|
||||
return count1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes to the file and ensures that no writes are reordered across this
|
||||
* request (acts as a barrier)
|
||||
*
|
||||
* Returns 0 on success, -errno in error cases.
|
||||
*/
|
||||
int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
|
||||
const void *buf, int count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bdrv_pwrite(bs, offset, buf, count);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* No flush needed for cache=writethrough, it uses O_DSYNC */
|
||||
if ((bs->open_flags & BDRV_O_CACHE_MASK) != 0) {
|
||||
bdrv_flush(bs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes to the file and ensures that no writes are reordered across this
|
||||
* request (acts as a barrier)
|
||||
*
|
||||
* Returns 0 on success, -errno in error cases.
|
||||
*/
|
||||
int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
return bdrv_pwrite_sync(bs, BDRV_SECTOR_SIZE * sector_num,
|
||||
buf, BDRV_SECTOR_SIZE * nb_sectors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate file to 'offset' bytes (needed only for file protocols)
|
||||
*/
|
||||
@@ -1606,8 +1647,11 @@ static void multiwrite_user_cb(MultiwriteCB *mcb)
|
||||
|
||||
for (i = 0; i < mcb->num_callbacks; i++) {
|
||||
mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
|
||||
if (mcb->callbacks[i].free_qiov) {
|
||||
qemu_iovec_destroy(mcb->callbacks[i].free_qiov);
|
||||
}
|
||||
qemu_free(mcb->callbacks[i].free_qiov);
|
||||
qemu_free(mcb->callbacks[i].free_buf);
|
||||
qemu_vfree(mcb->callbacks[i].free_buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1615,23 +1659,32 @@ static void multiwrite_cb(void *opaque, int ret)
|
||||
{
|
||||
MultiwriteCB *mcb = opaque;
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret < 0 && !mcb->error) {
|
||||
mcb->error = ret;
|
||||
multiwrite_user_cb(mcb);
|
||||
}
|
||||
|
||||
mcb->num_requests--;
|
||||
if (mcb->num_requests == 0) {
|
||||
if (mcb->error == 0) {
|
||||
multiwrite_user_cb(mcb);
|
||||
}
|
||||
multiwrite_user_cb(mcb);
|
||||
qemu_free(mcb);
|
||||
}
|
||||
}
|
||||
|
||||
static int multiwrite_req_compare(const void *a, const void *b)
|
||||
{
|
||||
return (((BlockRequest*) a)->sector - ((BlockRequest*) b)->sector);
|
||||
const BlockRequest *req1 = a, *req2 = b;
|
||||
|
||||
/*
|
||||
* Note that we can't simply subtract req2->sector from req1->sector
|
||||
* here as that could overflow the return value.
|
||||
*/
|
||||
if (req1->sector > req2->sector) {
|
||||
return 1;
|
||||
} else if (req1->sector < req2->sector) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1667,6 +1720,10 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
|
||||
merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]);
|
||||
}
|
||||
|
||||
if (reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1 > IOV_MAX) {
|
||||
merge = 0;
|
||||
}
|
||||
|
||||
if (merge) {
|
||||
size_t size;
|
||||
QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
|
||||
@@ -1690,7 +1747,7 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
|
||||
// Add the second request
|
||||
qemu_iovec_concat(qiov, reqs[i].qiov, reqs[i].qiov->size);
|
||||
|
||||
reqs[outidx].nb_sectors += reqs[i].nb_sectors;
|
||||
reqs[outidx].nb_sectors = qiov->size >> 9;
|
||||
reqs[outidx].qiov = qiov;
|
||||
|
||||
mcb->callbacks[i].free_qiov = reqs[outidx].qiov;
|
||||
@@ -1742,8 +1799,29 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
||||
// Check for mergable requests
|
||||
num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);
|
||||
|
||||
// Run the aio requests
|
||||
/*
|
||||
* Run the aio requests. As soon as one request can't be submitted
|
||||
* successfully, fail all requests that are not yet submitted (we must
|
||||
* return failure for all requests anyway)
|
||||
*
|
||||
* num_requests cannot be set to the right value immediately: If
|
||||
* bdrv_aio_writev fails for some request, num_requests would be too high
|
||||
* and therefore multiwrite_cb() would never recognize the multiwrite
|
||||
* request as completed. We also cannot use the loop variable i to set it
|
||||
* when the first request fails because the callback may already have been
|
||||
* called for previously submitted requests. Thus, num_requests must be
|
||||
* incremented for each request that is submitted.
|
||||
*
|
||||
* The problem that callbacks may be called early also means that we need
|
||||
* to take care that num_requests doesn't become 0 before all requests are
|
||||
* submitted - multiwrite_cb() would consider the multiwrite request
|
||||
* completed. A dummy request that is "completed" by a manual call to
|
||||
* multiwrite_cb() takes care of this.
|
||||
*/
|
||||
mcb->num_requests = 1;
|
||||
|
||||
for (i = 0; i < num_reqs; i++) {
|
||||
mcb->num_requests++;
|
||||
acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
|
||||
reqs[i].nb_sectors, multiwrite_cb, mcb);
|
||||
|
||||
@@ -1751,22 +1829,25 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
||||
// We can only fail the whole thing if no request has been
|
||||
// submitted yet. Otherwise we'll wait for the submitted AIOs to
|
||||
// complete and report the error in the callback.
|
||||
if (mcb->num_requests == 0) {
|
||||
reqs[i].error = EIO;
|
||||
if (i == 0) {
|
||||
goto fail;
|
||||
} else {
|
||||
mcb->error = EIO;
|
||||
multiwrite_cb(mcb, -EIO);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
mcb->num_requests++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Complete the dummy request */
|
||||
multiwrite_cb(mcb, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
free(mcb);
|
||||
for (i = 0; i < mcb->num_callbacks; i++) {
|
||||
reqs[i].error = -EIO;
|
||||
}
|
||||
qemu_free(mcb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,10 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
|
||||
void *buf, int count);
|
||||
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
|
||||
const void *buf, int count);
|
||||
int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
|
||||
const void *buf, int count);
|
||||
int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
|
||||
int64_t bdrv_getlength(BlockDriverState *bs);
|
||||
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
|
||||
|
||||
+1
-1
@@ -309,7 +309,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
|
||||
static int inited = 0;
|
||||
|
||||
file = strdup(filename);
|
||||
file = qemu_strdup(filename);
|
||||
s->readahead_size = READ_AHEAD_SIZE;
|
||||
|
||||
/* Parse a trailing ":readahead=#:" param, if present. */
|
||||
|
||||
+10
-8
@@ -277,8 +277,9 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
/* update the L1 entry */
|
||||
s->l1_table[l1_index] = l2_offset;
|
||||
tmp = cpu_to_be64(l2_offset);
|
||||
if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
|
||||
&tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
if (bdrv_pwrite_sync(s->hd,
|
||||
s->l1_table_offset + l1_index * sizeof(tmp),
|
||||
&tmp, sizeof(tmp)) < 0)
|
||||
return 0;
|
||||
new_l2_table = 1;
|
||||
}
|
||||
@@ -306,8 +307,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
l2_table = s->l2_cache + (min_index << s->l2_bits);
|
||||
if (new_l2_table) {
|
||||
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
|
||||
if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
if (bdrv_pwrite_sync(s->hd, l2_offset, l2_table,
|
||||
s->l2_size * sizeof(uint64_t)) < 0)
|
||||
return 0;
|
||||
} else {
|
||||
if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
@@ -372,8 +373,8 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
|
||||
/* update L2 table */
|
||||
tmp = cpu_to_be64(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
if (bdrv_pwrite(s->hd,
|
||||
l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
if (bdrv_pwrite_sync(s->hd, l2_offset + l2_index * sizeof(tmp),
|
||||
&tmp, sizeof(tmp)) < 0)
|
||||
return 0;
|
||||
}
|
||||
return cluster_offset;
|
||||
@@ -821,8 +822,9 @@ static int qcow_make_empty(BlockDriverState *bs)
|
||||
int ret;
|
||||
|
||||
memset(s->l1_table, 0, l1_length);
|
||||
if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0)
|
||||
return -1;
|
||||
if (bdrv_pwrite_sync(s->hd, s->l1_table_offset, s->l1_table,
|
||||
l1_length) < 0)
|
||||
return -1;
|
||||
ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
+107
-63
@@ -33,7 +33,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int new_l1_size, new_l1_size2, ret, i;
|
||||
uint64_t *new_l1_table;
|
||||
uint64_t new_l1_table_offset;
|
||||
int64_t new_l1_table_offset;
|
||||
uint8_t data[12];
|
||||
|
||||
new_l1_size = s->l1_size;
|
||||
@@ -55,11 +55,15 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
|
||||
|
||||
/* write new table (align to cluster) */
|
||||
new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
|
||||
if (new_l1_table_offset < 0) {
|
||||
qemu_free(new_l1_table);
|
||||
return new_l1_table_offset;
|
||||
}
|
||||
|
||||
for(i = 0; i < s->l1_size; i++)
|
||||
new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
|
||||
ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
|
||||
if (ret != new_l1_size2)
|
||||
ret = bdrv_pwrite_sync(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
for(i = 0; i < s->l1_size; i++)
|
||||
new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
|
||||
@@ -67,9 +71,10 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
|
||||
/* set new table */
|
||||
cpu_to_be32w((uint32_t*)data, new_l1_size);
|
||||
cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
|
||||
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,
|
||||
sizeof(data)) != sizeof(data))
|
||||
ret = bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data));
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
qemu_free(s->l1_table);
|
||||
qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
|
||||
s->l1_table_offset = new_l1_table_offset;
|
||||
@@ -77,8 +82,9 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
|
||||
s->l1_size = new_l1_size;
|
||||
return 0;
|
||||
fail:
|
||||
qemu_free(s->l1_table);
|
||||
return -EIO;
|
||||
qemu_free(new_l1_table);
|
||||
qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qcow2_l2_cache_reset(BlockDriverState *bs)
|
||||
@@ -182,17 +188,17 @@ static int write_l1_entry(BDRVQcowState *s, int l1_index)
|
||||
{
|
||||
uint64_t buf[L1_ENTRIES_PER_SECTOR];
|
||||
int l1_start_index;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
|
||||
for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
|
||||
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
|
||||
}
|
||||
|
||||
if (bdrv_pwrite(s->hd, s->l1_table_offset + 8 * l1_start_index,
|
||||
buf, sizeof(buf)) != sizeof(buf))
|
||||
{
|
||||
return -1;
|
||||
ret = bdrv_pwrite_sync(s->hd, s->l1_table_offset + 8 * l1_start_index,
|
||||
buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -213,18 +219,16 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int min_index;
|
||||
uint64_t old_l2_offset;
|
||||
uint64_t *l2_table, l2_offset;
|
||||
uint64_t *l2_table;
|
||||
int64_t l2_offset;
|
||||
int ret;
|
||||
|
||||
old_l2_offset = s->l1_table[l1_index];
|
||||
|
||||
/* allocate a new l2 entry */
|
||||
|
||||
l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
|
||||
|
||||
/* update the L1 entry */
|
||||
|
||||
s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
|
||||
if (write_l1_entry(s, l1_index) < 0) {
|
||||
if (l2_offset < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -241,13 +245,20 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
|
||||
if (bdrv_pread(s->hd, old_l2_offset,
|
||||
l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
/* write the l2 table to the file */
|
||||
if (bdrv_pwrite(s->hd, l2_offset,
|
||||
l2_table, s->l2_size * sizeof(uint64_t)) !=
|
||||
s->l2_size * sizeof(uint64_t))
|
||||
return NULL;
|
||||
ret = bdrv_pwrite_sync(s->hd, l2_offset, l2_table,
|
||||
s->l2_size * sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* update the L1 entry */
|
||||
s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
|
||||
if (write_l1_entry(s, l1_index) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* update the l2 cache entry */
|
||||
|
||||
@@ -255,6 +266,11 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
|
||||
s->l2_cache_counts[min_index] = 1;
|
||||
|
||||
return l2_table;
|
||||
|
||||
fail:
|
||||
s->l1_table[l1_index] = old_l2_offset;
|
||||
qcow2_l2_cache_reset(bs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
|
||||
@@ -370,8 +386,8 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect,
|
||||
s->cluster_data, n, 1,
|
||||
&s->aes_encrypt_key);
|
||||
}
|
||||
ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start,
|
||||
s->cluster_data, n);
|
||||
ret = bdrv_write_sync(s->hd, (cluster_offset >> 9) + n_start,
|
||||
s->cluster_data, n);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
@@ -479,8 +495,8 @@ out:
|
||||
* the l2 table offset in the qcow2 file and the cluster index
|
||||
* in the l2 table are given to the caller.
|
||||
*
|
||||
* Returns 0 on success, -errno in failure case
|
||||
*/
|
||||
|
||||
static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t **new_l2_table,
|
||||
uint64_t *new_l2_offset,
|
||||
@@ -496,8 +512,9 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
||||
l1_index = offset >> (s->l2_bits + s->cluster_bits);
|
||||
if (l1_index >= s->l1_size) {
|
||||
ret = qcow2_grow_l1_table(bs, l1_index + 1);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
l2_offset = s->l1_table[l1_index];
|
||||
|
||||
@@ -507,14 +524,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
||||
/* load the l2 table in memory */
|
||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
||||
l2_table = l2_load(bs, l2_offset);
|
||||
if (l2_table == NULL)
|
||||
return 0;
|
||||
if (l2_table == NULL) {
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
if (l2_offset)
|
||||
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
|
||||
l2_table = l2_allocate(bs, l1_index);
|
||||
if (l2_table == NULL)
|
||||
return 0;
|
||||
if (l2_table == NULL) {
|
||||
return -EIO;
|
||||
}
|
||||
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
|
||||
}
|
||||
|
||||
@@ -526,7 +545,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
|
||||
*new_l2_offset = l2_offset;
|
||||
*new_l2_index = l2_index;
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -548,12 +567,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int l2_index, ret;
|
||||
uint64_t l2_offset, *l2_table, cluster_offset;
|
||||
uint64_t l2_offset, *l2_table;
|
||||
int64_t cluster_offset;
|
||||
int nb_csectors;
|
||||
|
||||
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
|
||||
if (ret == 0)
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
||||
if (cluster_offset & QCOW_OFLAG_COPIED)
|
||||
@@ -563,6 +584,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
qcow2_free_any_clusters(bs, cluster_offset, 1);
|
||||
|
||||
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
|
||||
if (cluster_offset < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
|
||||
(cluster_offset >> 9);
|
||||
|
||||
@@ -574,10 +599,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
/* compressed clusters never have the copied flag */
|
||||
|
||||
l2_table[l2_index] = cpu_to_be64(cluster_offset);
|
||||
if (bdrv_pwrite(s->hd,
|
||||
if (bdrv_pwrite_sync(s->hd,
|
||||
l2_offset + l2_index * sizeof(uint64_t),
|
||||
l2_table + l2_index,
|
||||
sizeof(uint64_t)) != sizeof(uint64_t))
|
||||
sizeof(uint64_t)) < 0)
|
||||
return 0;
|
||||
|
||||
return cluster_offset;
|
||||
@@ -595,22 +620,23 @@ static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table,
|
||||
int start_offset = (8 * l2_index) & ~511;
|
||||
int end_offset = (8 * (l2_index + num) + 511) & ~511;
|
||||
size_t len = end_offset - start_offset;
|
||||
int ret;
|
||||
|
||||
if (bdrv_pwrite(s->hd, l2_offset + start_offset, &l2_table[l2_start_index],
|
||||
len) != len)
|
||||
{
|
||||
return -1;
|
||||
ret = bdrv_pwrite_sync(s->hd, l2_offset + start_offset,
|
||||
&l2_table[l2_start_index], len);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
|
||||
QCowL2Meta *m)
|
||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int i, j = 0, l2_index, ret;
|
||||
uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
|
||||
uint64_t cluster_offset = m->cluster_offset;
|
||||
|
||||
if (m->nb_clusters == 0)
|
||||
return 0;
|
||||
@@ -633,10 +659,11 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = -EIO;
|
||||
/* update L2 table */
|
||||
if (!get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index))
|
||||
ret = get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < m->nb_clusters; i++) {
|
||||
/* if two concurrent writes happen to the same unallocated cluster
|
||||
@@ -652,8 +679,9 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
|
||||
(i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
|
||||
}
|
||||
|
||||
if (write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters) < 0) {
|
||||
ret = -1;
|
||||
ret = write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters);
|
||||
if (ret < 0) {
|
||||
qcow2_l2_cache_reset(bs);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -670,30 +698,36 @@ err:
|
||||
/*
|
||||
* alloc_cluster_offset
|
||||
*
|
||||
* For a given offset of the disk image, return cluster offset in
|
||||
* qcow2 file.
|
||||
*
|
||||
* For a given offset of the disk image, return cluster offset in qcow2 file.
|
||||
* If the offset is not found, allocate a new cluster.
|
||||
*
|
||||
* Return the cluster offset if successful,
|
||||
* Return 0, otherwise.
|
||||
* If the cluster was already allocated, m->nb_clusters is set to 0,
|
||||
* m->depends_on is set to NULL and the other fields in m are meaningless.
|
||||
*
|
||||
* If the cluster is newly allocated, m->nb_clusters is set to the number of
|
||||
* contiguous clusters that have been allocated. This may be 0 if the request
|
||||
* conflict with another write request in flight; in this case, m->depends_on
|
||||
* is set and the remaining fields of m are meaningless.
|
||||
*
|
||||
* If m->nb_clusters is non-zero, the other fields of m are valid and contain
|
||||
* information about the first allocated cluster.
|
||||
*
|
||||
* Return 0 on success and -errno in error cases
|
||||
*/
|
||||
|
||||
uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int n_start, int n_end,
|
||||
int *num, QCowL2Meta *m)
|
||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int n_start, int n_end, int *num, QCowL2Meta *m)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int l2_index, ret;
|
||||
uint64_t l2_offset, *l2_table, cluster_offset;
|
||||
uint64_t l2_offset, *l2_table;
|
||||
int64_t cluster_offset;
|
||||
unsigned int nb_clusters, i = 0;
|
||||
QCowL2Meta *old_alloc;
|
||||
|
||||
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
nb_clusters = size_to_clusters(s, n_end << 9);
|
||||
|
||||
@@ -709,6 +743,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
||||
|
||||
cluster_offset &= ~QCOW_OFLAG_COPIED;
|
||||
m->nb_clusters = 0;
|
||||
m->depends_on = NULL;
|
||||
|
||||
goto out;
|
||||
}
|
||||
@@ -723,12 +758,15 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
||||
while (i < nb_clusters) {
|
||||
i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
|
||||
&l2_table[l2_index], i, 0);
|
||||
|
||||
if(be64_to_cpu(l2_table[l2_index + i]))
|
||||
if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
|
||||
break;
|
||||
}
|
||||
|
||||
i += count_contiguous_free_clusters(nb_clusters - i,
|
||||
&l2_table[l2_index + i]);
|
||||
if (i >= nb_clusters) {
|
||||
break;
|
||||
}
|
||||
|
||||
cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
|
||||
|
||||
@@ -736,6 +774,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
||||
(cluster_offset & QCOW_OFLAG_COMPRESSED))
|
||||
break;
|
||||
}
|
||||
assert(i <= nb_clusters);
|
||||
nb_clusters = i;
|
||||
|
||||
/*
|
||||
@@ -779,6 +818,10 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
||||
/* allocate a new cluster */
|
||||
|
||||
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
|
||||
if (cluster_offset < 0) {
|
||||
QLIST_REMOVE(m, next_in_flight);
|
||||
return cluster_offset;
|
||||
}
|
||||
|
||||
/* save info needed for meta data update */
|
||||
m->offset = offset;
|
||||
@@ -787,10 +830,11 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
||||
|
||||
out:
|
||||
m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
|
||||
m->cluster_offset = cluster_offset;
|
||||
|
||||
*num = m->nb_available - n_start;
|
||||
|
||||
return cluster_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
|
||||
|
||||
+319
-119
@@ -27,7 +27,7 @@
|
||||
#include "block/qcow2.h"
|
||||
|
||||
static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size);
|
||||
static int update_refcount(BlockDriverState *bs,
|
||||
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
int64_t offset, int64_t length,
|
||||
int addend);
|
||||
|
||||
@@ -42,8 +42,8 @@ static int write_refcount_block(BDRVQcowState *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bdrv_pwrite(s->hd, s->refcount_block_cache_offset,
|
||||
s->refcount_block_cache, size) != size)
|
||||
if (bdrv_pwrite_sync(s->hd, s->refcount_block_cache_offset,
|
||||
s->refcount_block_cache, size) < 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
@@ -123,121 +123,273 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
|
||||
return be16_to_cpu(s->refcount_block_cache[block_index]);
|
||||
}
|
||||
|
||||
static int grow_refcount_table(BlockDriverState *bs, int min_size)
|
||||
/*
|
||||
* Rounds the refcount table size up to avoid growing the table for each single
|
||||
* refcount block that is allocated.
|
||||
*/
|
||||
static unsigned int next_refcount_table_size(BDRVQcowState *s,
|
||||
unsigned int min_size)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int new_table_size, new_table_size2, refcount_table_clusters, i, ret;
|
||||
uint64_t *new_table;
|
||||
int64_t table_offset;
|
||||
uint8_t data[12];
|
||||
int old_table_size;
|
||||
int64_t old_table_offset;
|
||||
unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1;
|
||||
unsigned int refcount_table_clusters =
|
||||
MAX(1, s->refcount_table_size >> (s->cluster_bits - 3));
|
||||
|
||||
if (min_size <= s->refcount_table_size)
|
||||
return 0;
|
||||
/* compute new table size */
|
||||
refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
|
||||
for(;;) {
|
||||
if (refcount_table_clusters == 0) {
|
||||
refcount_table_clusters = 1;
|
||||
} else {
|
||||
refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
|
||||
}
|
||||
new_table_size = refcount_table_clusters << (s->cluster_bits - 3);
|
||||
if (min_size <= new_table_size)
|
||||
break;
|
||||
while (min_clusters > refcount_table_clusters) {
|
||||
refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2;
|
||||
}
|
||||
#ifdef DEBUG_ALLOC2
|
||||
printf("grow_refcount_table from %d to %d\n",
|
||||
s->refcount_table_size,
|
||||
new_table_size);
|
||||
#endif
|
||||
new_table_size2 = new_table_size * sizeof(uint64_t);
|
||||
new_table = qemu_mallocz(new_table_size2);
|
||||
memcpy(new_table, s->refcount_table,
|
||||
s->refcount_table_size * sizeof(uint64_t));
|
||||
for(i = 0; i < s->refcount_table_size; i++)
|
||||
cpu_to_be64s(&new_table[i]);
|
||||
/* Note: we cannot update the refcount now to avoid recursion */
|
||||
table_offset = alloc_clusters_noref(bs, new_table_size2);
|
||||
ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
|
||||
if (ret != new_table_size2)
|
||||
goto fail;
|
||||
for(i = 0; i < s->refcount_table_size; i++)
|
||||
be64_to_cpus(&new_table[i]);
|
||||
|
||||
cpu_to_be64w((uint64_t*)data, table_offset);
|
||||
cpu_to_be32w((uint32_t*)(data + 8), refcount_table_clusters);
|
||||
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
|
||||
data, sizeof(data)) != sizeof(data))
|
||||
goto fail;
|
||||
qemu_free(s->refcount_table);
|
||||
old_table_offset = s->refcount_table_offset;
|
||||
old_table_size = s->refcount_table_size;
|
||||
s->refcount_table = new_table;
|
||||
s->refcount_table_size = new_table_size;
|
||||
s->refcount_table_offset = table_offset;
|
||||
|
||||
update_refcount(bs, table_offset, new_table_size2, 1);
|
||||
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
|
||||
return 0;
|
||||
fail:
|
||||
qemu_free(new_table);
|
||||
return -EIO;
|
||||
return refcount_table_clusters << (s->cluster_bits - 3);
|
||||
}
|
||||
|
||||
|
||||
/* Checks if two offsets are described by the same refcount block */
|
||||
static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a,
|
||||
uint64_t offset_b)
|
||||
{
|
||||
uint64_t block_a = offset_a >> (2 * s->cluster_bits - REFCOUNT_SHIFT);
|
||||
uint64_t block_b = offset_b >> (2 * s->cluster_bits - REFCOUNT_SHIFT);
|
||||
|
||||
return (block_a == block_b);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads a refcount block. If it doesn't exist yet, it is allocated first
|
||||
* (including growing the refcount table if needed).
|
||||
*
|
||||
* Returns the offset of the refcount block on success or -errno in error case
|
||||
*/
|
||||
static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int64_t offset, refcount_block_offset;
|
||||
unsigned int refcount_table_index;
|
||||
int ret;
|
||||
uint64_t data64;
|
||||
int cache = cache_refcount_updates;
|
||||
|
||||
/* Find L1 index and grow refcount table if needed */
|
||||
/* Find the refcount block for the given cluster */
|
||||
refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
|
||||
if (refcount_table_index >= s->refcount_table_size) {
|
||||
ret = grow_refcount_table(bs, refcount_table_index + 1);
|
||||
if (ret < 0)
|
||||
|
||||
if (refcount_table_index < s->refcount_table_size) {
|
||||
|
||||
uint64_t refcount_block_offset =
|
||||
s->refcount_table[refcount_table_index];
|
||||
|
||||
/* If it's already there, we're done */
|
||||
if (refcount_block_offset) {
|
||||
if (refcount_block_offset != s->refcount_block_cache_offset) {
|
||||
ret = load_refcount_block(bs, refcount_block_offset);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return refcount_block_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we came here, we need to allocate something. Something is at least
|
||||
* a cluster for the new refcount block. It may also include a new refcount
|
||||
* table if the old refcount table is too small.
|
||||
*
|
||||
* Note that allocating clusters here needs some special care:
|
||||
*
|
||||
* - We can't use the normal qcow2_alloc_clusters(), it would try to
|
||||
* increase the refcount and very likely we would end up with an endless
|
||||
* recursion. Instead we must place the refcount blocks in a way that
|
||||
* they can describe them themselves.
|
||||
*
|
||||
* - We need to consider that at this point we are inside update_refcounts
|
||||
* and doing the initial refcount increase. This means that some clusters
|
||||
* have already been allocated by the caller, but their refcount isn't
|
||||
* accurate yet. free_cluster_index tells us where this allocation ends
|
||||
* as long as we don't overwrite it by freeing clusters.
|
||||
*
|
||||
* - alloc_clusters_noref and qcow2_free_clusters may load a different
|
||||
* refcount block into the cache
|
||||
*/
|
||||
|
||||
if (cache_refcount_updates) {
|
||||
ret = write_refcount_block(s);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load or allocate the refcount block */
|
||||
refcount_block_offset = s->refcount_table[refcount_table_index];
|
||||
if (!refcount_block_offset) {
|
||||
if (cache_refcount_updates) {
|
||||
write_refcount_block(s);
|
||||
cache_refcount_updates = 0;
|
||||
}
|
||||
/* create a new refcount block */
|
||||
/* Note: we cannot update the refcount now to avoid recursion */
|
||||
offset = alloc_clusters_noref(bs, s->cluster_size);
|
||||
/* Allocate the refcount block itself and mark it as used */
|
||||
uint64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
|
||||
|
||||
#ifdef DEBUG_ALLOC2
|
||||
fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
|
||||
" at %" PRIx64 "\n",
|
||||
refcount_table_index, cluster_index << s->cluster_bits, new_block);
|
||||
#endif
|
||||
|
||||
if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) {
|
||||
/* Zero the new refcount block before updating it */
|
||||
memset(s->refcount_block_cache, 0, s->cluster_size);
|
||||
ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size);
|
||||
if (ret != s->cluster_size)
|
||||
return -EINVAL;
|
||||
s->refcount_table[refcount_table_index] = offset;
|
||||
data64 = cpu_to_be64(offset);
|
||||
ret = bdrv_pwrite(s->hd, s->refcount_table_offset +
|
||||
refcount_table_index * sizeof(uint64_t),
|
||||
&data64, sizeof(data64));
|
||||
if (ret != sizeof(data64))
|
||||
return -EINVAL;
|
||||
s->refcount_block_cache_offset = new_block;
|
||||
|
||||
refcount_block_offset = offset;
|
||||
s->refcount_block_cache_offset = offset;
|
||||
update_refcount(bs, offset, s->cluster_size, 1);
|
||||
cache_refcount_updates = cache;
|
||||
/* The block describes itself, need to update the cache */
|
||||
int block_index = (new_block >> s->cluster_bits) &
|
||||
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
|
||||
s->refcount_block_cache[block_index] = cpu_to_be16(1);
|
||||
} else {
|
||||
if (refcount_block_offset != s->refcount_block_cache_offset) {
|
||||
if (load_refcount_block(bs, refcount_block_offset) < 0)
|
||||
return -EIO;
|
||||
/* Described somewhere else. This can recurse at most twice before we
|
||||
* arrive at a block that describes itself. */
|
||||
ret = update_refcount(bs, new_block, s->cluster_size, 1);
|
||||
if (ret < 0) {
|
||||
goto fail_block;
|
||||
}
|
||||
|
||||
/* Initialize the new refcount block only after updating its refcount,
|
||||
* update_refcount uses the refcount cache itself */
|
||||
memset(s->refcount_block_cache, 0, s->cluster_size);
|
||||
s->refcount_block_cache_offset = new_block;
|
||||
}
|
||||
|
||||
return refcount_block_offset;
|
||||
/* Now the new refcount block needs to be written to disk */
|
||||
ret = bdrv_pwrite_sync(s->hd, new_block, s->refcount_block_cache,
|
||||
s->cluster_size);
|
||||
if (ret < 0) {
|
||||
goto fail_block;
|
||||
}
|
||||
|
||||
/* If the refcount table is big enough, just hook the block up there */
|
||||
if (refcount_table_index < s->refcount_table_size) {
|
||||
uint64_t data64 = cpu_to_be64(new_block);
|
||||
ret = bdrv_pwrite_sync(s->hd,
|
||||
s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
|
||||
&data64, sizeof(data64));
|
||||
if (ret < 0) {
|
||||
goto fail_block;
|
||||
}
|
||||
|
||||
s->refcount_table[refcount_table_index] = new_block;
|
||||
return new_block;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we come here, we need to grow the refcount table. Again, a new
|
||||
* refcount table needs some space and we can't simply allocate to avoid
|
||||
* endless recursion.
|
||||
*
|
||||
* Therefore let's grab new refcount blocks at the end of the image, which
|
||||
* will describe themselves and the new refcount table. This way we can
|
||||
* reference them only in the new table and do the switch to the new
|
||||
* refcount table at once without producing an inconsistent state in
|
||||
* between.
|
||||
*/
|
||||
/* Calculate the number of refcount blocks needed so far */
|
||||
uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
|
||||
uint64_t blocks_used = (s->free_cluster_index +
|
||||
refcount_block_clusters - 1) / refcount_block_clusters;
|
||||
|
||||
/* And now we need at least one block more for the new metadata */
|
||||
uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
|
||||
uint64_t last_table_size;
|
||||
uint64_t blocks_clusters;
|
||||
do {
|
||||
uint64_t table_clusters = size_to_clusters(s, table_size);
|
||||
blocks_clusters = 1 +
|
||||
((table_clusters + refcount_block_clusters - 1)
|
||||
/ refcount_block_clusters);
|
||||
uint64_t meta_clusters = table_clusters + blocks_clusters;
|
||||
|
||||
last_table_size = table_size;
|
||||
table_size = next_refcount_table_size(s, blocks_used +
|
||||
((meta_clusters + refcount_block_clusters - 1)
|
||||
/ refcount_block_clusters));
|
||||
|
||||
} while (last_table_size != table_size);
|
||||
|
||||
#ifdef DEBUG_ALLOC2
|
||||
fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
|
||||
s->refcount_table_size, table_size);
|
||||
#endif
|
||||
|
||||
/* Create the new refcount table and blocks */
|
||||
uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
|
||||
s->cluster_size;
|
||||
uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
|
||||
uint16_t *new_blocks = qemu_mallocz(blocks_clusters * s->cluster_size);
|
||||
uint64_t *new_table = qemu_mallocz(table_size * sizeof(uint64_t));
|
||||
|
||||
assert(meta_offset >= (s->free_cluster_index * s->cluster_size));
|
||||
|
||||
/* Fill the new refcount table */
|
||||
memcpy(new_table, s->refcount_table,
|
||||
s->refcount_table_size * sizeof(uint64_t));
|
||||
new_table[refcount_table_index] = new_block;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < blocks_clusters; i++) {
|
||||
new_table[blocks_used + i] = meta_offset + (i * s->cluster_size);
|
||||
}
|
||||
|
||||
/* Fill the refcount blocks */
|
||||
uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
|
||||
int block = 0;
|
||||
for (i = 0; i < table_clusters + blocks_clusters; i++) {
|
||||
new_blocks[block++] = cpu_to_be16(1);
|
||||
}
|
||||
|
||||
/* Write refcount blocks to disk */
|
||||
ret = bdrv_pwrite_sync(s->hd, meta_offset, new_blocks,
|
||||
blocks_clusters * s->cluster_size);
|
||||
qemu_free(new_blocks);
|
||||
if (ret < 0) {
|
||||
goto fail_table;
|
||||
}
|
||||
|
||||
/* Write refcount table to disk */
|
||||
for(i = 0; i < table_size; i++) {
|
||||
cpu_to_be64s(&new_table[i]);
|
||||
}
|
||||
|
||||
ret = bdrv_pwrite_sync(s->hd, table_offset, new_table,
|
||||
table_size * sizeof(uint64_t));
|
||||
if (ret < 0) {
|
||||
goto fail_table;
|
||||
}
|
||||
|
||||
for(i = 0; i < table_size; i++) {
|
||||
cpu_to_be64s(&new_table[i]);
|
||||
}
|
||||
|
||||
/* Hook up the new refcount table in the qcow2 header */
|
||||
uint8_t data[12];
|
||||
cpu_to_be64w((uint64_t*)data, table_offset);
|
||||
cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
|
||||
ret = bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, refcount_table_offset),
|
||||
data, sizeof(data));
|
||||
if (ret < 0) {
|
||||
goto fail_table;
|
||||
}
|
||||
|
||||
/* And switch it in memory */
|
||||
uint64_t old_table_offset = s->refcount_table_offset;
|
||||
uint64_t old_table_size = s->refcount_table_size;
|
||||
|
||||
qemu_free(s->refcount_table);
|
||||
s->refcount_table = new_table;
|
||||
s->refcount_table_size = table_size;
|
||||
s->refcount_table_offset = table_offset;
|
||||
|
||||
/* Free old table. Remember, we must not change free_cluster_index */
|
||||
uint64_t old_free_cluster_index = s->free_cluster_index;
|
||||
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
|
||||
s->free_cluster_index = old_free_cluster_index;
|
||||
|
||||
ret = load_refcount_block(bs, new_block);
|
||||
if (ret < 0) {
|
||||
goto fail_block;
|
||||
}
|
||||
|
||||
return new_block;
|
||||
|
||||
fail_table:
|
||||
qemu_free(new_table);
|
||||
fail_block:
|
||||
s->refcount_block_cache_offset = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT)
|
||||
@@ -245,43 +397,52 @@ static int write_refcount_block_entries(BDRVQcowState *s,
|
||||
int64_t refcount_block_offset, int first_index, int last_index)
|
||||
{
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
if (cache_refcount_updates) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (first_index < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
first_index &= ~(REFCOUNTS_PER_SECTOR - 1);
|
||||
last_index = (last_index + REFCOUNTS_PER_SECTOR)
|
||||
& ~(REFCOUNTS_PER_SECTOR - 1);
|
||||
|
||||
size = (last_index - first_index) << REFCOUNT_SHIFT;
|
||||
if (bdrv_pwrite(s->hd,
|
||||
ret = bdrv_pwrite_sync(s->hd,
|
||||
refcount_block_offset + (first_index << REFCOUNT_SHIFT),
|
||||
&s->refcount_block_cache[first_index], size) != size)
|
||||
{
|
||||
return -EIO;
|
||||
&s->refcount_block_cache[first_index], size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: cache several refcount block clusters ? */
|
||||
static int update_refcount(BlockDriverState *bs,
|
||||
int64_t offset, int64_t length,
|
||||
int addend)
|
||||
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
|
||||
int64_t offset, int64_t length, int addend)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int64_t start, last, cluster_offset;
|
||||
int64_t refcount_block_offset = 0;
|
||||
int64_t table_index = -1, old_table_index;
|
||||
int first_index = -1, last_index = -1;
|
||||
int ret;
|
||||
|
||||
#ifdef DEBUG_ALLOC2
|
||||
printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
|
||||
offset, length, addend);
|
||||
#endif
|
||||
if (length <= 0)
|
||||
if (length < 0) {
|
||||
return -EINVAL;
|
||||
} else if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
start = offset & ~(s->cluster_size - 1);
|
||||
last = (offset + length - 1) & ~(s->cluster_size - 1);
|
||||
for(cluster_offset = start; cluster_offset <= last;
|
||||
@@ -289,6 +450,7 @@ static int update_refcount(BlockDriverState *bs,
|
||||
{
|
||||
int block_index, refcount;
|
||||
int64_t cluster_index = cluster_offset >> s->cluster_bits;
|
||||
int64_t new_block;
|
||||
|
||||
/* Only write refcount block to disk when we are done with it */
|
||||
old_table_index = table_index;
|
||||
@@ -306,10 +468,12 @@ static int update_refcount(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
/* Load the refcount block and allocate it if needed */
|
||||
refcount_block_offset = alloc_refcount_block(bs, cluster_index);
|
||||
if (refcount_block_offset < 0) {
|
||||
return refcount_block_offset;
|
||||
new_block = alloc_refcount_block(bs, cluster_index);
|
||||
if (new_block < 0) {
|
||||
ret = new_block;
|
||||
goto fail;
|
||||
}
|
||||
refcount_block_offset = new_block;
|
||||
|
||||
/* we can update the count and save it */
|
||||
block_index = cluster_index &
|
||||
@@ -323,24 +487,38 @@ static int update_refcount(BlockDriverState *bs,
|
||||
|
||||
refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
|
||||
refcount += addend;
|
||||
if (refcount < 0 || refcount > 0xffff)
|
||||
return -EINVAL;
|
||||
if (refcount < 0 || refcount > 0xffff) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (refcount == 0 && cluster_index < s->free_cluster_index) {
|
||||
s->free_cluster_index = cluster_index;
|
||||
}
|
||||
s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
|
||||
/* Write last changed block to disk */
|
||||
if (refcount_block_offset != 0) {
|
||||
if (write_refcount_block_entries(s, refcount_block_offset,
|
||||
first_index, last_index) < 0)
|
||||
{
|
||||
return -EIO;
|
||||
return ret < 0 ? ret : -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* Try do undo any updates if an error is returned (This may succeed in
|
||||
* some cases like ENOSPC for allocating a new refcount block)
|
||||
*/
|
||||
if (ret < 0) {
|
||||
int dummy;
|
||||
dummy = update_refcount(bs, offset, cluster_offset - offset, -addend);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* addend must be 1 or -1 */
|
||||
@@ -390,9 +568,13 @@ retry:
|
||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
|
||||
{
|
||||
int64_t offset;
|
||||
int ret;
|
||||
|
||||
offset = alloc_clusters_noref(bs, size);
|
||||
update_refcount(bs, offset, size, 1);
|
||||
ret = update_refcount(bs, offset, size, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -407,6 +589,9 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
||||
assert(size > 0 && size <= s->cluster_size);
|
||||
if (s->free_byte_offset == 0) {
|
||||
s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
|
||||
if (s->free_byte_offset < 0) {
|
||||
return s->free_byte_offset;
|
||||
}
|
||||
}
|
||||
redo:
|
||||
free_in_cluster = s->cluster_size -
|
||||
@@ -422,6 +607,9 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
||||
update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
|
||||
} else {
|
||||
offset = qcow2_alloc_clusters(bs, s->cluster_size);
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
|
||||
if ((cluster_offset + s->cluster_size) == offset) {
|
||||
/* we are lucky: contiguous data */
|
||||
@@ -439,7 +627,13 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
|
||||
void qcow2_free_clusters(BlockDriverState *bs,
|
||||
int64_t offset, int64_t size)
|
||||
{
|
||||
update_refcount(bs, offset, size, -1);
|
||||
int ret;
|
||||
|
||||
ret = update_refcount(bs, offset, size, -1);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
|
||||
/* TODO Remember the clusters to free them later and avoid leaking */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -549,9 +743,15 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
if (offset & QCOW_OFLAG_COMPRESSED) {
|
||||
nb_csectors = ((offset >> s->csize_shift) &
|
||||
s->csize_mask) + 1;
|
||||
if (addend != 0)
|
||||
update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
|
||||
nb_csectors * 512, addend);
|
||||
if (addend != 0) {
|
||||
int ret;
|
||||
ret = update_refcount(bs,
|
||||
(offset & s->cluster_offset_mask) & ~511,
|
||||
nb_csectors * 512, addend);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
/* compressed clusters are never modified */
|
||||
refcount = 2;
|
||||
} else {
|
||||
@@ -572,8 +772,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
if (l2_modified) {
|
||||
if (bdrv_pwrite(s->hd,
|
||||
l2_offset, l2_table, l2_size) != l2_size)
|
||||
if (bdrv_pwrite_sync(s->hd,
|
||||
l2_offset, l2_table, l2_size) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -594,8 +794,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
if (l1_modified) {
|
||||
for(i = 0; i < l1_size; i++)
|
||||
cpu_to_be64s(&l1_table[i]);
|
||||
if (bdrv_pwrite(s->hd, l1_table_offset, l1_table,
|
||||
l1_size2) != l1_size2)
|
||||
if (bdrv_pwrite_sync(s->hd, l1_table_offset, l1_table,
|
||||
l1_size2) < 0)
|
||||
goto fail;
|
||||
for(i = 0; i < l1_size; i++)
|
||||
be64_to_cpus(&l1_table[i]);
|
||||
|
||||
+21
-13
@@ -139,6 +139,9 @@ static int qcow_write_snapshots(BlockDriverState *bs)
|
||||
|
||||
snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
|
||||
offset = snapshots_offset;
|
||||
if (offset < 0) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
for(i = 0; i < s->nb_snapshots; i++) {
|
||||
sn = s->snapshots + i;
|
||||
@@ -155,25 +158,25 @@ static int qcow_write_snapshots(BlockDriverState *bs)
|
||||
h.id_str_size = cpu_to_be16(id_str_size);
|
||||
h.name_size = cpu_to_be16(name_size);
|
||||
offset = align_offset(offset, 8);
|
||||
if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h))
|
||||
if (bdrv_pwrite_sync(s->hd, offset, &h, sizeof(h)) < 0)
|
||||
goto fail;
|
||||
offset += sizeof(h);
|
||||
if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size)
|
||||
if (bdrv_pwrite_sync(s->hd, offset, sn->id_str, id_str_size) < 0)
|
||||
goto fail;
|
||||
offset += id_str_size;
|
||||
if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size)
|
||||
if (bdrv_pwrite_sync(s->hd, offset, sn->name, name_size) < 0)
|
||||
goto fail;
|
||||
offset += name_size;
|
||||
}
|
||||
|
||||
/* update the various header fields */
|
||||
data64 = cpu_to_be64(snapshots_offset);
|
||||
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset),
|
||||
&data64, sizeof(data64)) != sizeof(data64))
|
||||
if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, snapshots_offset),
|
||||
&data64, sizeof(data64)) < 0)
|
||||
goto fail;
|
||||
data32 = cpu_to_be32(s->nb_snapshots);
|
||||
if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots),
|
||||
&data32, sizeof(data32)) != sizeof(data32))
|
||||
if (bdrv_pwrite_sync(s->hd, offsetof(QCowHeader, nb_snapshots),
|
||||
&data32, sizeof(data32)) < 0)
|
||||
goto fail;
|
||||
|
||||
/* free the old snapshot table */
|
||||
@@ -235,6 +238,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
QCowSnapshot *snapshots1, sn1, *sn = &sn1;
|
||||
int i, ret;
|
||||
uint64_t *l1_table = NULL;
|
||||
int64_t l1_table_offset;
|
||||
|
||||
memset(sn, 0, sizeof(*sn));
|
||||
|
||||
@@ -263,7 +267,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
goto fail;
|
||||
|
||||
/* create the L1 table of the snapshot */
|
||||
sn->l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
|
||||
l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
|
||||
if (l1_table_offset < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sn->l1_table_offset = l1_table_offset;
|
||||
sn->l1_size = s->l1_size;
|
||||
|
||||
if (s->l1_size != 0) {
|
||||
@@ -275,9 +284,8 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
for(i = 0; i < s->l1_size; i++) {
|
||||
l1_table[i] = cpu_to_be64(s->l1_table[i]);
|
||||
}
|
||||
if (bdrv_pwrite(s->hd, sn->l1_table_offset,
|
||||
l1_table, s->l1_size * sizeof(uint64_t)) !=
|
||||
(s->l1_size * sizeof(uint64_t)))
|
||||
if (bdrv_pwrite_sync(s->hd, sn->l1_table_offset,
|
||||
l1_table, s->l1_size * sizeof(uint64_t)) < 0)
|
||||
goto fail;
|
||||
qemu_free(l1_table);
|
||||
l1_table = NULL;
|
||||
@@ -326,8 +334,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||
if (bdrv_pread(s->hd, sn->l1_table_offset,
|
||||
s->l1_table, l1_size2) != l1_size2)
|
||||
goto fail;
|
||||
if (bdrv_pwrite(s->hd, s->l1_table_offset,
|
||||
s->l1_table, l1_size2) != l1_size2)
|
||||
if (bdrv_pwrite_sync(s->hd, s->l1_table_offset,
|
||||
s->l1_table, l1_size2) < 0)
|
||||
goto fail;
|
||||
for(i = 0;i < s->l1_size; i++) {
|
||||
be64_to_cpus(&s->l1_table[i]);
|
||||
|
||||
+65
-31
@@ -467,8 +467,10 @@ static void qcow_aio_read_cb(void *opaque, int ret)
|
||||
acb->hd_aiocb = bdrv_aio_readv(s->hd,
|
||||
(acb->cluster_offset >> 9) + index_in_cluster,
|
||||
&acb->hd_qiov, acb->n, qcow_aio_read_cb, acb);
|
||||
if (acb->hd_aiocb == NULL)
|
||||
if (acb->hd_aiocb == NULL) {
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -561,7 +563,7 @@ static void qcow_aio_write_cb(void *opaque, int ret)
|
||||
acb->hd_aiocb = NULL;
|
||||
|
||||
if (ret >= 0) {
|
||||
ret = qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta);
|
||||
ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta);
|
||||
}
|
||||
|
||||
run_dependent_requests(&acb->l2meta);
|
||||
@@ -585,21 +587,23 @@ static void qcow_aio_write_cb(void *opaque, int ret)
|
||||
n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
|
||||
n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
|
||||
|
||||
acb->cluster_offset = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
|
||||
index_in_cluster,
|
||||
n_end, &acb->n, &acb->l2meta);
|
||||
ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
|
||||
index_in_cluster, n_end, &acb->n, &acb->l2meta);
|
||||
if (ret < 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
acb->cluster_offset = acb->l2meta.cluster_offset;
|
||||
|
||||
/* Need to wait for another request? If so, we are done for now. */
|
||||
if (!acb->cluster_offset && acb->l2meta.depends_on != NULL) {
|
||||
if (acb->l2meta.nb_clusters == 0 && acb->l2meta.depends_on != NULL) {
|
||||
QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests,
|
||||
acb, next_depend);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!acb->cluster_offset || (acb->cluster_offset & 511) != 0) {
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
assert((acb->cluster_offset & 511) == 0);
|
||||
|
||||
if (s->crypt_method) {
|
||||
if (!acb->cluster_data) {
|
||||
acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS *
|
||||
@@ -618,11 +622,17 @@ static void qcow_aio_write_cb(void *opaque, int ret)
|
||||
(acb->cluster_offset >> 9) + index_in_cluster,
|
||||
&acb->hd_qiov, acb->n,
|
||||
qcow_aio_write_cb, acb);
|
||||
if (acb->hd_aiocb == NULL)
|
||||
goto done;
|
||||
if (acb->hd_aiocb == NULL) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (acb->l2meta.nb_clusters != 0) {
|
||||
QLIST_REMOVE(&acb->l2meta, next_in_flight);
|
||||
}
|
||||
done:
|
||||
if (acb->qiov->niov > 1)
|
||||
qemu_vfree(acb->orig_buf);
|
||||
@@ -683,27 +693,27 @@ static int get_bits_from_size(size_t size)
|
||||
static int preallocate(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t cluster_offset = 0;
|
||||
uint64_t nb_sectors;
|
||||
uint64_t offset;
|
||||
int num;
|
||||
int ret;
|
||||
QCowL2Meta meta;
|
||||
|
||||
nb_sectors = bdrv_getlength(bs) >> 9;
|
||||
offset = 0;
|
||||
QLIST_INIT(&meta.dependent_requests);
|
||||
meta.cluster_offset = 0;
|
||||
|
||||
while (nb_sectors) {
|
||||
num = MIN(nb_sectors, INT_MAX >> 9);
|
||||
cluster_offset = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
|
||||
&meta);
|
||||
ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num, &meta);
|
||||
|
||||
if (cluster_offset == 0) {
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qcow2_alloc_cluster_link_l2(bs, cluster_offset, &meta) < 0) {
|
||||
qcow2_free_any_clusters(bs, cluster_offset, meta.nb_clusters);
|
||||
if (qcow2_alloc_cluster_link_l2(bs, &meta) < 0) {
|
||||
qcow2_free_any_clusters(bs, meta.cluster_offset, meta.nb_clusters);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -722,10 +732,10 @@ static int preallocate(BlockDriverState *bs)
|
||||
* all of the allocated clusters (otherwise we get failing reads after
|
||||
* EOF). Extend the image to the last allocated sector.
|
||||
*/
|
||||
if (cluster_offset != 0) {
|
||||
if (meta.cluster_offset != 0) {
|
||||
uint8_t buf[512];
|
||||
memset(buf, 0, 512);
|
||||
bdrv_write(s->hd, (cluster_offset >> 9) + num - 1, buf, 1);
|
||||
bdrv_write(s->hd, (meta.cluster_offset >> 9) + num - 1, buf, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -737,10 +747,11 @@ static int qcow_create2(const char *filename, int64_t total_size,
|
||||
{
|
||||
|
||||
int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
|
||||
int ref_clusters, backing_format_len = 0;
|
||||
int ref_clusters, reftable_clusters, backing_format_len = 0;
|
||||
int rounded_ext_bf_len = 0;
|
||||
QCowHeader header;
|
||||
uint64_t tmp, offset;
|
||||
uint64_t old_ref_clusters;
|
||||
QCowCreateState s1, *s = &s1;
|
||||
QCowExtension ext_bf = {0, 0};
|
||||
|
||||
@@ -799,17 +810,37 @@ static int qcow_create2(const char *filename, int64_t total_size,
|
||||
header.l1_size = cpu_to_be32(l1_size);
|
||||
offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
|
||||
|
||||
s->refcount_table = qemu_mallocz(s->cluster_size);
|
||||
/* count how many refcount blocks needed */
|
||||
|
||||
#define NUM_CLUSTERS(bytes) \
|
||||
(((bytes) + (s->cluster_size) - 1) / (s->cluster_size))
|
||||
|
||||
ref_clusters = NUM_CLUSTERS(NUM_CLUSTERS(offset) * sizeof(uint16_t));
|
||||
|
||||
do {
|
||||
uint64_t image_clusters;
|
||||
old_ref_clusters = ref_clusters;
|
||||
|
||||
/* Number of clusters used for the refcount table */
|
||||
reftable_clusters = NUM_CLUSTERS(ref_clusters * sizeof(uint64_t));
|
||||
|
||||
/* Number of clusters that the whole image will have */
|
||||
image_clusters = NUM_CLUSTERS(offset) + ref_clusters
|
||||
+ reftable_clusters;
|
||||
|
||||
/* Number of refcount blocks needed for the image */
|
||||
ref_clusters = NUM_CLUSTERS(image_clusters * sizeof(uint16_t));
|
||||
|
||||
} while (ref_clusters != old_ref_clusters);
|
||||
|
||||
s->refcount_table = qemu_mallocz(reftable_clusters * s->cluster_size);
|
||||
|
||||
s->refcount_table_offset = offset;
|
||||
header.refcount_table_offset = cpu_to_be64(offset);
|
||||
header.refcount_table_clusters = cpu_to_be32(1);
|
||||
offset += s->cluster_size;
|
||||
header.refcount_table_clusters = cpu_to_be32(reftable_clusters);
|
||||
offset += (reftable_clusters * s->cluster_size);
|
||||
s->refcount_block_offset = offset;
|
||||
|
||||
/* count how many refcount blocks needed */
|
||||
tmp = offset >> s->cluster_bits;
|
||||
ref_clusters = (tmp >> (s->cluster_bits - REFCOUNT_SHIFT)) + 1;
|
||||
for (i=0; i < ref_clusters; i++) {
|
||||
s->refcount_table[i] = cpu_to_be64(offset);
|
||||
offset += s->cluster_size;
|
||||
@@ -821,7 +852,8 @@ static int qcow_create2(const char *filename, int64_t total_size,
|
||||
qcow2_create_refcount_update(s, 0, header_size);
|
||||
qcow2_create_refcount_update(s, s->l1_table_offset,
|
||||
l1_size * sizeof(uint64_t));
|
||||
qcow2_create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
|
||||
qcow2_create_refcount_update(s, s->refcount_table_offset,
|
||||
reftable_clusters * s->cluster_size);
|
||||
qcow2_create_refcount_update(s, s->refcount_block_offset,
|
||||
ref_clusters * s->cluster_size);
|
||||
|
||||
@@ -849,7 +881,8 @@ static int qcow_create2(const char *filename, int64_t total_size,
|
||||
write(fd, &tmp, sizeof(tmp));
|
||||
}
|
||||
lseek(fd, s->refcount_table_offset, SEEK_SET);
|
||||
write(fd, s->refcount_table, s->cluster_size);
|
||||
write(fd, s->refcount_table,
|
||||
reftable_clusters * s->cluster_size);
|
||||
|
||||
lseek(fd, s->refcount_block_offset, SEEK_SET);
|
||||
write(fd, s->refcount_block, ref_clusters * s->cluster_size);
|
||||
@@ -1056,12 +1089,13 @@ static int qcow_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int growable = bs->growable;
|
||||
int ret;
|
||||
|
||||
bs->growable = 1;
|
||||
bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size);
|
||||
ret = bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size);
|
||||
bs->growable = growable;
|
||||
|
||||
return size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf,
|
||||
|
||||
+4
-6
@@ -135,6 +135,7 @@ struct QCowAIOCB;
|
||||
typedef struct QCowL2Meta
|
||||
{
|
||||
uint64_t offset;
|
||||
uint64_t cluster_offset;
|
||||
int n_start;
|
||||
int nb_available;
|
||||
int nb_clusters;
|
||||
@@ -191,16 +192,13 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
||||
|
||||
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int *num);
|
||||
uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int n_start, int n_end,
|
||||
int *num, QCowL2Meta *m);
|
||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int n_start, int n_end, int *num, QCowL2Meta *m);
|
||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int compressed_size);
|
||||
|
||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
|
||||
QCowL2Meta *m);
|
||||
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
|
||||
|
||||
/* qcow2-snapshot.c functions */
|
||||
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
|
||||
|
||||
+1
-1
@@ -595,7 +595,7 @@ static void raw_close(BlockDriverState *bs)
|
||||
close(s->fd);
|
||||
s->fd = -1;
|
||||
if (s->aligned_buf != NULL)
|
||||
qemu_free(s->aligned_buf);
|
||||
qemu_vfree(s->aligned_buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-3
@@ -399,6 +399,15 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
vdi_header_print(&header);
|
||||
#endif
|
||||
|
||||
if (header.disk_size % SECTOR_SIZE != 0) {
|
||||
/* 'VBoxManage convertfromraw' can create images with odd disk sizes.
|
||||
We accept them but round the disk size to the next multiple of
|
||||
SECTOR_SIZE. */
|
||||
logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size);
|
||||
header.disk_size += SECTOR_SIZE - 1;
|
||||
header.disk_size &= ~(SECTOR_SIZE - 1);
|
||||
}
|
||||
|
||||
if (header.version != VDI_VERSION_1_1) {
|
||||
logout("unsupported version %u.%u\n",
|
||||
header.version >> 16, header.version & 0xffff);
|
||||
@@ -417,9 +426,9 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
} else if (header.block_size != 1 * MiB) {
|
||||
logout("unsupported block size %u B\n", header.block_size);
|
||||
goto fail;
|
||||
} else if (header.disk_size !=
|
||||
} else if (header.disk_size >
|
||||
(uint64_t)header.blocks_in_image * header.block_size) {
|
||||
logout("unexpected block number %u B\n", header.blocks_in_image);
|
||||
logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
|
||||
goto fail;
|
||||
} else if (!uuid_is_null(header.uuid_link)) {
|
||||
logout("link uuid != 0, unsupported\n");
|
||||
@@ -831,7 +840,10 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
blocks = bytes / block_size;
|
||||
/* We need enough blocks to store the given disk size,
|
||||
so always round up. */
|
||||
blocks = (bytes + block_size - 1) / block_size;
|
||||
|
||||
bmap_size = blocks * sizeof(uint32_t);
|
||||
bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
|
||||
|
||||
|
||||
+17
-30
@@ -87,14 +87,6 @@ typedef struct VmdkMetaData {
|
||||
int valid;
|
||||
} VmdkMetaData;
|
||||
|
||||
typedef struct ActiveBDRVState{
|
||||
BlockDriverState *hd; // active image handler
|
||||
uint64_t cluster_offset; // current write offset
|
||||
}ActiveBDRVState;
|
||||
|
||||
static ActiveBDRVState activeBDRV;
|
||||
|
||||
|
||||
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
uint32_t magic;
|
||||
@@ -161,7 +153,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
|
||||
pstrcat(desc, sizeof(desc), tmp_desc);
|
||||
}
|
||||
|
||||
if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
|
||||
if (bdrv_pwrite_sync(s->hd, 0x200, desc, DESC_SIZE) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -285,7 +277,6 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file)
|
||||
goto fail_rgd;
|
||||
if (write(snp_fd, rgd_buf, gd_size) == -1)
|
||||
goto fail_rgd;
|
||||
qemu_free(rgd_buf);
|
||||
|
||||
/* write GD */
|
||||
gd_buf = qemu_malloc(gd_size);
|
||||
@@ -298,6 +289,7 @@ static int vmdk_snapshot_create(const char *filename, const char *backing_file)
|
||||
if (write(snp_fd, gd_buf, gd_size) == -1)
|
||||
goto fail_gd;
|
||||
qemu_free(gd_buf);
|
||||
qemu_free(rgd_buf);
|
||||
|
||||
close(p_fd);
|
||||
close(snp_fd);
|
||||
@@ -458,30 +450,28 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
|
||||
static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
|
||||
uint64_t offset, int allocate)
|
||||
{
|
||||
uint64_t parent_cluster_offset;
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
uint8_t whole_grain[s->cluster_sectors*512]; // 128 sectors * 512 bytes each = grain size 64KB
|
||||
|
||||
// we will be here if it's first write on non-exist grain(cluster).
|
||||
// try to read from parent image, if exist
|
||||
if (bs->backing_hd) {
|
||||
BDRVVmdkState *ps = bs->backing_hd->opaque;
|
||||
int ret;
|
||||
|
||||
if (!vmdk_is_cid_valid(bs))
|
||||
return -1;
|
||||
|
||||
parent_cluster_offset = get_cluster_offset(bs->backing_hd, NULL,
|
||||
offset, allocate);
|
||||
ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
|
||||
s->cluster_sectors);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parent_cluster_offset) {
|
||||
BDRVVmdkState *act_s = activeBDRV.hd->opaque;
|
||||
|
||||
if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512)
|
||||
return -1;
|
||||
|
||||
//Write grain only into the active image
|
||||
if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain))
|
||||
return -1;
|
||||
//Write grain only into the active image
|
||||
ret = bdrv_write(s->hd, cluster_offset, whole_grain,
|
||||
s->cluster_sectors);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -492,14 +482,14 @@ static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
|
||||
/* update L2 table */
|
||||
if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
&(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
|
||||
if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
&(m_data->offset), sizeof(m_data->offset)) < 0)
|
||||
return -1;
|
||||
/* update backup L2 table */
|
||||
if (s->l1_backup_table_offset != 0) {
|
||||
m_data->l2_offset = s->l1_backup_table[m_data->l1_index];
|
||||
if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
&(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
|
||||
if (bdrv_pwrite_sync(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
|
||||
&(m_data->offset), sizeof(m_data->offset)) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -567,9 +557,6 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
|
||||
cluster_offset >>= 9;
|
||||
tmp = cpu_to_le32(cluster_offset);
|
||||
l2_table[l2_index] = tmp;
|
||||
// Save the active image state
|
||||
activeBDRV.cluster_offset = cluster_offset;
|
||||
activeBDRV.hd = bs;
|
||||
}
|
||||
/* First of all we write grain itself, to avoid race condition
|
||||
* that may to corrupt the image.
|
||||
|
||||
+17
-13
@@ -266,7 +266,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
|
||||
|
||||
s->last_bitmap_offset = bitmap_offset;
|
||||
memset(bitmap, 0xff, s->bitmap_size);
|
||||
bdrv_pwrite(s->hd, bitmap_offset, bitmap, s->bitmap_size);
|
||||
bdrv_pwrite_sync(s->hd, bitmap_offset, bitmap, s->bitmap_size);
|
||||
}
|
||||
|
||||
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
|
||||
@@ -316,7 +316,7 @@ static int rewrite_footer(BlockDriverState* bs)
|
||||
BDRVVPCState *s = bs->opaque;
|
||||
int64_t offset = s->free_data_block_offset;
|
||||
|
||||
ret = bdrv_pwrite(s->hd, offset, s->footer_buf, HEADER_SIZE);
|
||||
ret = bdrv_pwrite_sync(s->hd, offset, s->footer_buf, HEADER_SIZE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -351,7 +351,8 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
|
||||
|
||||
// Initialize the block's bitmap
|
||||
memset(bitmap, 0xff, s->bitmap_size);
|
||||
bdrv_pwrite(s->hd, s->free_data_block_offset, bitmap, s->bitmap_size);
|
||||
bdrv_pwrite_sync(s->hd, s->free_data_block_offset, bitmap,
|
||||
s->bitmap_size);
|
||||
|
||||
// Write new footer (the old one will be overwritten)
|
||||
s->free_data_block_offset += s->block_size + s->bitmap_size;
|
||||
@@ -362,7 +363,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
|
||||
// Write BAT entry to disk
|
||||
bat_offset = s->bat_offset + (4 * index);
|
||||
bat_value = be32_to_cpu(s->pagetable[index]);
|
||||
ret = bdrv_pwrite(s->hd, bat_offset, &bat_value, 4);
|
||||
ret = bdrv_pwrite_sync(s->hd, bat_offset, &bat_value, 4);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
@@ -470,9 +471,7 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Rounding up deviates from the Virtual PC behaviour
|
||||
// However, we need this to avoid truncating images in qemu-img convert
|
||||
*cyls = (cyls_times_heads + *heads - 1) / *heads;
|
||||
*cyls = cyls_times_heads / *heads;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -484,9 +483,9 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
|
||||
struct vhd_dyndisk_header* dyndisk_header =
|
||||
(struct vhd_dyndisk_header*) buf;
|
||||
int fd, i;
|
||||
uint16_t cyls;
|
||||
uint8_t heads;
|
||||
uint8_t secs_per_cyl;
|
||||
uint16_t cyls = 0;
|
||||
uint8_t heads = 0;
|
||||
uint8_t secs_per_cyl = 0;
|
||||
size_t block_size, num_bat_entries;
|
||||
int64_t total_sectors = 0;
|
||||
|
||||
@@ -503,9 +502,14 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
|
||||
// Calculate matching total_size and geometry
|
||||
if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl))
|
||||
return -EFBIG;
|
||||
/* Calculate matching total_size and geometry. Increase the number of
|
||||
sectors requested until we get enough (or fail). */
|
||||
for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
|
||||
if (calculate_geometry(total_sectors + i,
|
||||
&cyls, &heads, &secs_per_cyl)) {
|
||||
return -EFBIG;
|
||||
}
|
||||
}
|
||||
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
|
||||
|
||||
// Prepare the Hard Disk Footer
|
||||
|
||||
+12
-7
@@ -868,7 +868,8 @@ static int init_directories(BDRVVVFATState* s,
|
||||
{
|
||||
direntry_t* entry=array_get_next(&(s->directory));
|
||||
entry->attributes=0x28; /* archive | volume label */
|
||||
snprintf((char*)entry->name,11,"QEMU VVFAT");
|
||||
memcpy(entry->name,"QEMU VVF",8);
|
||||
memcpy(entry->extension,"AT ",3);
|
||||
}
|
||||
|
||||
/* Now build FAT, and write back information into directory */
|
||||
@@ -882,7 +883,7 @@ static int init_directories(BDRVVVFATState* s,
|
||||
mapping->dir_index = 0;
|
||||
mapping->info.dir.parent_mapping_index = -1;
|
||||
mapping->first_mapping_index = -1;
|
||||
mapping->path = strdup(dirname);
|
||||
mapping->path = qemu_strdup(dirname);
|
||||
i = strlen(mapping->path);
|
||||
if (i > 0 && mapping->path[i - 1] == '/')
|
||||
mapping->path[i - 1] = '\0';
|
||||
@@ -1632,10 +1633,10 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
|
||||
|
||||
/* rename */
|
||||
if (strcmp(basename, basename2))
|
||||
schedule_rename(s, cluster_num, strdup(path));
|
||||
schedule_rename(s, cluster_num, qemu_strdup(path));
|
||||
} else if (is_file(direntry))
|
||||
/* new file */
|
||||
schedule_new_file(s, strdup(path), cluster_num);
|
||||
schedule_new_file(s, qemu_strdup(path), cluster_num);
|
||||
else {
|
||||
assert(0);
|
||||
return 0;
|
||||
@@ -1752,10 +1753,10 @@ static int check_directory_consistency(BDRVVVFATState *s,
|
||||
mapping->mode &= ~MODE_DELETED;
|
||||
|
||||
if (strcmp(basename, basename2))
|
||||
schedule_rename(s, cluster_num, strdup(path));
|
||||
schedule_rename(s, cluster_num, qemu_strdup(path));
|
||||
} else
|
||||
/* new directory */
|
||||
schedule_mkdir(s, cluster_num, strdup(path));
|
||||
schedule_mkdir(s, cluster_num, qemu_strdup(path));
|
||||
|
||||
lfn_init(&lfn);
|
||||
do {
|
||||
@@ -2256,7 +2257,11 @@ static int commit_one_file(BDRVVVFATState* s,
|
||||
c = c1;
|
||||
}
|
||||
|
||||
ftruncate(fd, size);
|
||||
if (ftruncate(fd, size)) {
|
||||
perror("ftruncate()");
|
||||
close(fd);
|
||||
return -4;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return commit_mappings(s, first_cluster, dir_index);
|
||||
|
||||
@@ -127,6 +127,7 @@ struct BlockDriverState {
|
||||
int64_t total_sectors; /* if we are reading a disk image, give its
|
||||
size in sectors */
|
||||
int read_only; /* if true, the media is read only */
|
||||
int open_flags; /* flags used to open the file, re-used for re-open */
|
||||
int removable; /* if true, the media can be removed */
|
||||
int locked; /* if true, the media cannot temporarily be ejected */
|
||||
int encrypted; /* if true, the media is encrypted */
|
||||
|
||||
+7
-5
@@ -232,11 +232,13 @@ int cpu_exec(CPUState *env1)
|
||||
|
||||
env_to_regs();
|
||||
#if defined(TARGET_I386)
|
||||
/* put eflags in CPU temporary format */
|
||||
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
DF = 1 - (2 * ((env->eflags >> 10) & 1));
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
if (!kvm_enabled()) {
|
||||
/* put eflags in CPU temporary format */
|
||||
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
DF = 1 - (2 * ((env->eflags >> 10) & 1));
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
}
|
||||
#elif defined(TARGET_SPARC)
|
||||
#elif defined(TARGET_M68K)
|
||||
env->cc_op = CC_OP_FLAGS;
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
|
||||
CONFIG_USB_OHCI=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
@@ -2,3 +2,4 @@
|
||||
|
||||
CONFIG_USB_OHCI=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
+3
-3
@@ -69,9 +69,9 @@ extern int printf(const char *, ...);
|
||||
#define AREG1 "r14"
|
||||
#define AREG2 "r15"
|
||||
#elif defined(__mips__)
|
||||
#define AREG0 "fp"
|
||||
#define AREG1 "s0"
|
||||
#define AREG2 "s1"
|
||||
#define AREG0 "s0"
|
||||
#define AREG1 "s1"
|
||||
#define AREG2 "fp"
|
||||
#elif defined(__sparc__)
|
||||
#ifdef CONFIG_SOLARIS
|
||||
#define AREG0 "g2"
|
||||
|
||||
@@ -3307,7 +3307,7 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
|
||||
if (is_write) {
|
||||
cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
|
||||
}
|
||||
qemu_free(bounce.buffer);
|
||||
qemu_vfree(bounce.buffer);
|
||||
bounce.buffer = NULL;
|
||||
cpu_notify_map_clients();
|
||||
}
|
||||
|
||||
+2
-2
@@ -71,7 +71,7 @@ static void arm_timer_recalibrate(arm_timer_state *s, int reload)
|
||||
{
|
||||
uint32_t limit;
|
||||
|
||||
if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
|
||||
if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
|
||||
/* Free running. */
|
||||
if (s->control & TIMER_CTRL_32BIT)
|
||||
limit = 0xffffffff;
|
||||
@@ -113,7 +113,7 @@ static void arm_timer_write(void *opaque, target_phys_addr_t offset,
|
||||
case 1: freq >>= 4; break;
|
||||
case 2: freq >>= 8; break;
|
||||
}
|
||||
arm_timer_recalibrate(s, 0);
|
||||
arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
|
||||
ptimer_set_freq(s->timer, freq);
|
||||
if (s->control & TIMER_CTRL_ENABLE) {
|
||||
/* Restart the timer if still enabled. */
|
||||
|
||||
+4
-2
@@ -2585,9 +2585,11 @@ static void map_linear_vram(CirrusVGAState *s)
|
||||
|
||||
static void unmap_linear_vram(CirrusVGAState *s)
|
||||
{
|
||||
if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end)
|
||||
if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
|
||||
s->vga.map_addr = s->vga.map_end = 0;
|
||||
|
||||
cpu_register_physical_memory(s->vga.lfb_addr, s->vga.vram_size,
|
||||
s->cirrus_linear_io_addr);
|
||||
}
|
||||
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
|
||||
s->vga.vga_io_memory);
|
||||
}
|
||||
|
||||
@@ -370,9 +370,9 @@ enum {
|
||||
FD_CMD_PART_ID = 0x18,
|
||||
FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
|
||||
FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
|
||||
FD_CMD_SAVE = 0x2c,
|
||||
FD_CMD_SAVE = 0x2e,
|
||||
FD_CMD_OPTION = 0x33,
|
||||
FD_CMD_RESTORE = 0x4c,
|
||||
FD_CMD_RESTORE = 0x4e,
|
||||
FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
|
||||
FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
|
||||
FD_CMD_FORMAT_AND_WRITE = 0xcd,
|
||||
@@ -1860,8 +1860,12 @@ fdctrl_t *fdctrl_init_isa(DriveInfo **fds)
|
||||
ISADevice *dev;
|
||||
|
||||
dev = isa_create("isa-fdc");
|
||||
qdev_prop_set_drive(&dev->qdev, "driveA", fds[0]);
|
||||
qdev_prop_set_drive(&dev->qdev, "driveB", fds[1]);
|
||||
if (fds[0]) {
|
||||
qdev_prop_set_drive(&dev->qdev, "driveA", fds[0]);
|
||||
}
|
||||
if (fds[1]) {
|
||||
qdev_prop_set_drive(&dev->qdev, "driveB", fds[1]);
|
||||
}
|
||||
if (qdev_init(&dev->qdev) < 0)
|
||||
return NULL;
|
||||
return &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state);
|
||||
@@ -1879,8 +1883,12 @@ fdctrl_t *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
|
||||
sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
|
||||
fdctrl = &sys->state;
|
||||
fdctrl->dma_chann = dma_chann; /* FIXME */
|
||||
qdev_prop_set_drive(dev, "driveA", fds[0]);
|
||||
qdev_prop_set_drive(dev, "driveB", fds[1]);
|
||||
if (fds[0]) {
|
||||
qdev_prop_set_drive(dev, "driveA", fds[0]);
|
||||
}
|
||||
if (fds[1]) {
|
||||
qdev_prop_set_drive(dev, "driveB", fds[1]);
|
||||
}
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_connect_irq(&sys->busdev, 0, irq);
|
||||
sysbus_mmio_map(&sys->busdev, 0, mmio_base);
|
||||
@@ -1896,7 +1904,9 @@ fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
|
||||
fdctrl_t *fdctrl;
|
||||
|
||||
dev = qdev_create(NULL, "SUNW,fdtwo");
|
||||
qdev_prop_set_drive(dev, "drive", fds[0]);
|
||||
if (fds[0]) {
|
||||
qdev_prop_set_drive(dev, "drive", fds[0]);
|
||||
}
|
||||
qdev_init_nofail(dev);
|
||||
sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
|
||||
fdctrl = &sys->state;
|
||||
|
||||
+1
-1
@@ -179,7 +179,7 @@ static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
|
||||
|
||||
static void put_unused(QEMUFile *f, void *pv, size_t size)
|
||||
{
|
||||
fprintf(stderr, "uint32_as_uint16 is only used for backward compatibilty.\n");
|
||||
fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
|
||||
fprintf(stderr, "This functions shouldn't be called.\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
#ifndef HW_IDE_H
|
||||
#define HW_IDE_H
|
||||
|
||||
#include "qdev.h"
|
||||
#include "isa.h"
|
||||
#include "pci.h"
|
||||
|
||||
/* ide-isa.c */
|
||||
int isa_ide_init(int iobase, int iobase2, int isairq,
|
||||
DriveInfo *hd0, DriveInfo *hd1);
|
||||
ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
|
||||
DriveInfo *hd0, DriveInfo *hd1);
|
||||
|
||||
/* ide-pci.c */
|
||||
void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
|
||||
int secondary_ide_enabled);
|
||||
void pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
|
||||
void pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
|
||||
PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
|
||||
PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
|
||||
|
||||
/* ide-macio.c */
|
||||
int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
|
||||
@@ -22,4 +23,6 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
|
||||
qemu_irq irq, int shift,
|
||||
DriveInfo *hd0, DriveInfo *hd1);
|
||||
|
||||
void ide_get_bs(BlockDriverState *bs[], BusState *qbus);
|
||||
|
||||
#endif /* HW_IDE_H */
|
||||
+2
-5
@@ -70,11 +70,7 @@ static void ide_map(PCIDevice *pci_dev, int region_num,
|
||||
|
||||
static PCIIDEState *pci_from_bm(BMDMAState *bm)
|
||||
{
|
||||
if (bm->unit == 0) {
|
||||
return container_of(bm, PCIIDEState, bmdma[0]);
|
||||
} else {
|
||||
return container_of(bm, PCIIDEState, bmdma[1]);
|
||||
}
|
||||
return bm->pci_dev;
|
||||
}
|
||||
|
||||
static uint32_t bmdma_readb(void *opaque, uint32_t addr)
|
||||
@@ -145,6 +141,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
|
||||
BMDMAState *bm = &d->bmdma[i];
|
||||
d->bus[i].bmdma = bm;
|
||||
bm->bus = d->bus+i;
|
||||
bm->pci_dev = d;
|
||||
qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
|
||||
|
||||
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
|
||||
|
||||
+73
-13
@@ -115,7 +115,7 @@ static void ide_identify(IDEState *s)
|
||||
put_le16(p + 20, 3); /* XXX: retired, remove ? */
|
||||
put_le16(p + 21, 512); /* cache size in sectors */
|
||||
put_le16(p + 22, 4); /* ecc bytes */
|
||||
padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */
|
||||
padstr((char *)(p + 23), s->version, 8); /* firmware version */
|
||||
padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
|
||||
#if MAX_MULT_SECTORS > 1
|
||||
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
|
||||
@@ -186,7 +186,7 @@ static void ide_atapi_identify(IDEState *s)
|
||||
put_le16(p + 20, 3); /* buffer type */
|
||||
put_le16(p + 21, 512); /* cache size in sectors */
|
||||
put_le16(p + 22, 4); /* ecc bytes */
|
||||
padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */
|
||||
padstr((char *)(p + 23), s->version, 8); /* firmware version */
|
||||
padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */
|
||||
put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
|
||||
#ifdef USE_DMA_CDROM
|
||||
@@ -238,7 +238,7 @@ static void ide_cfata_identify(IDEState *s)
|
||||
put_le16(p + 8, s->nb_sectors); /* Sectors per card */
|
||||
padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
|
||||
put_le16(p + 22, 0x0004); /* ECC bytes */
|
||||
padstr((char *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */
|
||||
padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */
|
||||
padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
|
||||
#if MAX_MULT_SECTORS > 1
|
||||
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
|
||||
@@ -1591,7 +1591,7 @@ static void ide_atapi_cmd(IDEState *s)
|
||||
buf[7] = 0; /* reserved */
|
||||
padstr8(buf + 8, 8, "QEMU");
|
||||
padstr8(buf + 16, 16, "QEMU DVD-ROM");
|
||||
padstr8(buf + 32, 4, QEMU_VERSION);
|
||||
padstr8(buf + 32, 4, s->version);
|
||||
ide_atapi_cmd_reply(s, 36, max_len);
|
||||
break;
|
||||
case GPCMD_GET_CONFIGURATION:
|
||||
@@ -2590,7 +2590,7 @@ void ide_bus_reset(IDEBus *bus)
|
||||
ide_clear_hob(bus);
|
||||
}
|
||||
|
||||
void ide_init_drive(IDEState *s, DriveInfo *dinfo)
|
||||
void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version)
|
||||
{
|
||||
int cylinders, heads, secs;
|
||||
uint64_t nb_sectors;
|
||||
@@ -2619,6 +2619,11 @@ void ide_init_drive(IDEState *s, DriveInfo *dinfo)
|
||||
if (strlen(s->drive_serial_str) == 0)
|
||||
snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
|
||||
"QM%05d", s->drive_serial);
|
||||
if (version) {
|
||||
pstrcpy(s->version, sizeof(s->version), version);
|
||||
} else {
|
||||
pstrcpy(s->version, sizeof(s->version), QEMU_VERSION);
|
||||
}
|
||||
ide_reset(s);
|
||||
}
|
||||
|
||||
@@ -2635,13 +2640,14 @@ void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
|
||||
s->unit = i;
|
||||
s->drive_serial = drive_serial++;
|
||||
s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
|
||||
s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
|
||||
s->smart_selftest_data = qemu_blockalign(s->bs, 512);
|
||||
s->sector_write_timer = qemu_new_timer(vm_clock,
|
||||
ide_sector_write_timer_cb, s);
|
||||
if (i == 0)
|
||||
ide_init_drive(s, hd0);
|
||||
ide_init_drive(s, hd0, NULL);
|
||||
if (i == 1)
|
||||
ide_init_drive(s, hd1);
|
||||
ide_init_drive(s, hd1, NULL);
|
||||
}
|
||||
bus->irq = irq;
|
||||
}
|
||||
@@ -2669,6 +2675,25 @@ static bool is_identify_set(void *opaque, int version_id)
|
||||
return s->identify_set != 0;
|
||||
}
|
||||
|
||||
static EndTransferFunc* transfer_end_table[] = {
|
||||
ide_sector_read,
|
||||
ide_sector_write,
|
||||
ide_transfer_stop,
|
||||
ide_atapi_cmd_reply_end,
|
||||
ide_atapi_cmd,
|
||||
};
|
||||
|
||||
static int transfer_end_table_idx(EndTransferFunc *fn)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
|
||||
if (transfer_end_table[i] == fn)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ide_drive_post_load(void *opaque, int version_id)
|
||||
{
|
||||
IDEState *s = opaque;
|
||||
@@ -2679,14 +2704,42 @@ static int ide_drive_post_load(void *opaque, int version_id)
|
||||
s->cdrom_changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->cur_io_buffer_len) {
|
||||
s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
|
||||
s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
|
||||
s->data_end = s->data_ptr + s->cur_io_buffer_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ide_drive_pre_save(void *opaque)
|
||||
{
|
||||
IDEState *s = opaque;
|
||||
|
||||
s->cur_io_buffer_len = 0;
|
||||
|
||||
if (!(s->status & DRQ_STAT))
|
||||
return;
|
||||
|
||||
s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
|
||||
s->cur_io_buffer_len = s->data_end - s->data_ptr;
|
||||
|
||||
s->end_transfer_fn_idx = transfer_end_table_idx(s->end_transfer_func);
|
||||
if (s->end_transfer_fn_idx == -1) {
|
||||
fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
|
||||
__func__);
|
||||
s->end_transfer_fn_idx = 2;
|
||||
}
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_ide_drive = {
|
||||
.name = "ide_drive",
|
||||
.version_id = 3,
|
||||
.version_id = 4,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.pre_save = ide_drive_pre_save,
|
||||
.post_load = ide_drive_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_INT32(mult_sectors, IDEState),
|
||||
@@ -2709,7 +2762,14 @@ const VMStateDescription vmstate_ide_drive = {
|
||||
VMSTATE_UINT8(sense_key, IDEState),
|
||||
VMSTATE_UINT8(asc, IDEState),
|
||||
VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
|
||||
/* XXX: if a transfer is pending, we do not save it yet */
|
||||
VMSTATE_INT32_V(req_nb_sectors, IDEState, 4),
|
||||
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 4,
|
||||
vmstate_info_uint8, uint8_t),
|
||||
VMSTATE_INT32_V(cur_io_buffer_offset, IDEState, 4),
|
||||
VMSTATE_INT32_V(cur_io_buffer_len, IDEState, 4),
|
||||
VMSTATE_UINT8_V(end_transfer_fn_idx, IDEState, 4),
|
||||
VMSTATE_INT32_V(elementary_transfer_size, IDEState, 4),
|
||||
VMSTATE_INT32_V(packet_transfer_size, IDEState, 4),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
@@ -2767,10 +2827,6 @@ static void ide_dma_restart(IDEState *s, int is_read)
|
||||
void ide_dma_cancel(BMDMAState *bm)
|
||||
{
|
||||
if (bm->status & BM_STATUS_DMAING) {
|
||||
bm->status &= ~BM_STATUS_DMAING;
|
||||
/* cancel DMA request */
|
||||
bm->unit = -1;
|
||||
bm->dma_cb = NULL;
|
||||
if (bm->aiocb) {
|
||||
#ifdef DEBUG_AIO
|
||||
printf("aio_cancel\n");
|
||||
@@ -2778,6 +2834,10 @@ void ide_dma_cancel(BMDMAState *bm)
|
||||
bdrv_aio_cancel(bm->aiocb);
|
||||
bm->aiocb = NULL;
|
||||
}
|
||||
bm->status &= ~BM_STATUS_DMAING;
|
||||
/* cancel DMA request */
|
||||
bm->unit = -1;
|
||||
bm->dma_cb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -397,6 +397,7 @@ struct IDEState {
|
||||
/* set for lba48 access */
|
||||
uint8_t lba48;
|
||||
BlockDriverState *bs;
|
||||
char version[9];
|
||||
/* ATAPI specific */
|
||||
uint8_t sense_key;
|
||||
uint8_t asc;
|
||||
@@ -416,6 +417,11 @@ struct IDEState {
|
||||
uint8_t *data_ptr;
|
||||
uint8_t *data_end;
|
||||
uint8_t *io_buffer;
|
||||
/* PIO save/restore */
|
||||
int32_t io_buffer_total_len;
|
||||
int cur_io_buffer_offset;
|
||||
int cur_io_buffer_len;
|
||||
uint8_t end_transfer_fn_idx;
|
||||
QEMUTimer *sector_write_timer; /* only used for win2k install hack */
|
||||
uint32_t irq_count; /* counts IRQs when using win2k install hack */
|
||||
/* CF-ATA extended error */
|
||||
@@ -449,6 +455,7 @@ struct IDEDevice {
|
||||
DeviceState qdev;
|
||||
uint32_t unit;
|
||||
DriveInfo *dinfo;
|
||||
char *version;
|
||||
};
|
||||
|
||||
typedef int (*ide_qdev_initfn)(IDEDevice *dev);
|
||||
@@ -474,6 +481,7 @@ struct BMDMAState {
|
||||
uint8_t status;
|
||||
uint32_t addr;
|
||||
|
||||
struct PCIIDEState *pci_dev;
|
||||
IDEBus *bus;
|
||||
/* current transfer state */
|
||||
uint32_t cur_addr;
|
||||
@@ -548,7 +556,7 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr);
|
||||
void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t ide_data_readl(void *opaque, uint32_t addr);
|
||||
|
||||
void ide_init_drive(IDEState *s, DriveInfo *dinfo);
|
||||
void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version);
|
||||
void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
|
||||
qemu_irq irq);
|
||||
void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
|
||||
|
||||
+4
-4
@@ -75,8 +75,8 @@ static int isa_ide_initfn(ISADevice *dev)
|
||||
return 0;
|
||||
};
|
||||
|
||||
int isa_ide_init(int iobase, int iobase2, int isairq,
|
||||
DriveInfo *hd0, DriveInfo *hd1)
|
||||
ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
|
||||
DriveInfo *hd0, DriveInfo *hd1)
|
||||
{
|
||||
ISADevice *dev;
|
||||
ISAIDEState *s;
|
||||
@@ -86,14 +86,14 @@ int isa_ide_init(int iobase, int iobase2, int isairq,
|
||||
qdev_prop_set_uint32(&dev->qdev, "iobase2", iobase2);
|
||||
qdev_prop_set_uint32(&dev->qdev, "irq", isairq);
|
||||
if (qdev_init(&dev->qdev) < 0)
|
||||
return -1;
|
||||
return NULL;
|
||||
|
||||
s = DO_UPCAST(ISAIDEState, dev, dev);
|
||||
if (hd0)
|
||||
ide_create_drive(&s->bus, 0, hd0);
|
||||
if (hd1)
|
||||
ide_create_drive(&s->bus, 1, hd1);
|
||||
return 0;
|
||||
return dev;
|
||||
}
|
||||
|
||||
static ISADeviceInfo isa_ide_info = {
|
||||
|
||||
+5
-2
@@ -78,6 +78,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
|
||||
BMDMAState *bm = &d->bmdma[i];
|
||||
d->bus[i].bmdma = bm;
|
||||
bm->bus = d->bus+i;
|
||||
bm->pci_dev = d;
|
||||
qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
|
||||
|
||||
register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
|
||||
@@ -157,22 +158,24 @@ static int pci_piix4_ide_initfn(PCIDevice *dev)
|
||||
|
||||
/* hd_table must contain 4 block drivers */
|
||||
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
|
||||
void pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
|
||||
PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
|
||||
{
|
||||
PCIDevice *dev;
|
||||
|
||||
dev = pci_create_simple(bus, devfn, "piix3-ide");
|
||||
pci_ide_create_devs(dev, hd_table);
|
||||
return dev;
|
||||
}
|
||||
|
||||
/* hd_table must contain 4 block drivers */
|
||||
/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
|
||||
void pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
|
||||
PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
|
||||
{
|
||||
PCIDevice *dev;
|
||||
|
||||
dev = pci_create_simple(bus, devfn, "piix4-ide");
|
||||
pci_ide_create_devs(dev, hd_table);
|
||||
return dev;
|
||||
}
|
||||
|
||||
static PCIDeviceInfo piix_ide_info[] = {
|
||||
|
||||
+9
-1
@@ -90,6 +90,13 @@ IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
|
||||
return DO_UPCAST(IDEDevice, qdev, dev);
|
||||
}
|
||||
|
||||
void ide_get_bs(BlockDriverState *bs[], BusState *qbus)
|
||||
{
|
||||
IDEBus *bus = DO_UPCAST(IDEBus, qbus, qbus);
|
||||
bs[0] = bus->master ? bus->master->dinfo->bdrv : NULL;
|
||||
bs[1] = bus->slave ? bus->slave->dinfo->bdrv : NULL;
|
||||
}
|
||||
|
||||
/* --------------------------------- */
|
||||
|
||||
typedef struct IDEDrive {
|
||||
@@ -99,7 +106,7 @@ typedef struct IDEDrive {
|
||||
static int ide_drive_initfn(IDEDevice *dev)
|
||||
{
|
||||
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
|
||||
ide_init_drive(bus->ifs + dev->unit, dev->dinfo);
|
||||
ide_init_drive(bus->ifs + dev->unit, dev->dinfo, dev->version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -110,6 +117,7 @@ static IDEDeviceInfo ide_drive_info = {
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1),
|
||||
DEFINE_PROP_DRIVE("drive", IDEDrive, dev.dinfo),
|
||||
DEFINE_PROP_STRING("ver", IDEDrive, dev.version),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
+84
-92
@@ -173,11 +173,15 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
|
||||
/* Flag set if this is a tagged command. */
|
||||
#define LSI_TAG_VALID (1 << 16)
|
||||
|
||||
typedef struct {
|
||||
typedef struct lsi_request {
|
||||
uint32_t tag;
|
||||
SCSIDevice *dev;
|
||||
uint32_t dma_len;
|
||||
uint8_t *dma_buf;
|
||||
uint32_t pending;
|
||||
int out;
|
||||
} lsi_queue;
|
||||
QTAILQ_ENTRY(lsi_request) next;
|
||||
} lsi_request;
|
||||
|
||||
typedef struct {
|
||||
PCIDevice dev;
|
||||
@@ -198,16 +202,13 @@ typedef struct {
|
||||
* 3 if a DMA operation is in progress. */
|
||||
int waiting;
|
||||
SCSIBus bus;
|
||||
SCSIDevice *current_dev;
|
||||
SCSIDevice *select_dev;
|
||||
int current_lun;
|
||||
/* The tag is a combination of the device ID and the SCSI tag. */
|
||||
uint32_t current_tag;
|
||||
uint32_t current_dma_len;
|
||||
uint32_t select_tag;
|
||||
int command_complete;
|
||||
uint8_t *dma_buf;
|
||||
lsi_queue *queue;
|
||||
int queue_len;
|
||||
int active_commands;
|
||||
QTAILQ_HEAD(, lsi_request) queue;
|
||||
lsi_request *current;
|
||||
|
||||
uint32_t dsa;
|
||||
uint32_t temp;
|
||||
@@ -370,7 +371,7 @@ static int lsi_dma_64bit(LSIState *s)
|
||||
static uint8_t lsi_reg_readb(LSIState *s, int offset);
|
||||
static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
|
||||
static void lsi_execute_script(LSIState *s);
|
||||
static void lsi_reselect(LSIState *s, uint32_t tag);
|
||||
static void lsi_reselect(LSIState *s, lsi_request *p);
|
||||
|
||||
static inline uint32_t read_dword(LSIState *s, uint32_t addr)
|
||||
{
|
||||
@@ -391,9 +392,9 @@ static void lsi_stop_script(LSIState *s)
|
||||
|
||||
static void lsi_update_irq(LSIState *s)
|
||||
{
|
||||
int i;
|
||||
int level;
|
||||
static int last_level;
|
||||
lsi_request *p;
|
||||
|
||||
/* It's unclear whether the DIP/SIP bits should be cleared when the
|
||||
Interrupt Status Registers are cleared or when istat0 is read.
|
||||
@@ -427,9 +428,9 @@ static void lsi_update_irq(LSIState *s)
|
||||
if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
|
||||
DPRINTF("Handled IRQs & disconnected, looking for pending "
|
||||
"processes\n");
|
||||
for (i = 0; i < s->active_commands; i++) {
|
||||
if (s->queue[i].pending) {
|
||||
lsi_reselect(s, s->queue[i].tag);
|
||||
QTAILQ_FOREACH(p, &s->queue, next) {
|
||||
if (p->pending) {
|
||||
lsi_reselect(s, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -508,15 +509,16 @@ static void lsi_do_dma(LSIState *s, int out)
|
||||
uint32_t count;
|
||||
target_phys_addr_t addr;
|
||||
|
||||
if (!s->current_dma_len) {
|
||||
assert(s->current);
|
||||
if (!s->current->dma_len) {
|
||||
/* Wait until data is available. */
|
||||
DPRINTF("DMA no data available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
count = s->dbc;
|
||||
if (count > s->current_dma_len)
|
||||
count = s->current_dma_len;
|
||||
if (count > s->current->dma_len)
|
||||
count = s->current->dma_len;
|
||||
|
||||
addr = s->dnad;
|
||||
/* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
|
||||
@@ -532,29 +534,29 @@ static void lsi_do_dma(LSIState *s, int out)
|
||||
s->dnad += count;
|
||||
s->dbc -= count;
|
||||
|
||||
if (s->dma_buf == NULL) {
|
||||
s->dma_buf = s->current_dev->info->get_buf(s->current_dev,
|
||||
s->current_tag);
|
||||
if (s->current->dma_buf == NULL) {
|
||||
s->current->dma_buf = s->current->dev->info->get_buf(s->current->dev,
|
||||
s->current->tag);
|
||||
}
|
||||
|
||||
/* ??? Set SFBR to first data byte. */
|
||||
if (out) {
|
||||
cpu_physical_memory_read(addr, s->dma_buf, count);
|
||||
cpu_physical_memory_read(addr, s->current->dma_buf, count);
|
||||
} else {
|
||||
cpu_physical_memory_write(addr, s->dma_buf, count);
|
||||
cpu_physical_memory_write(addr, s->current->dma_buf, count);
|
||||
}
|
||||
s->current_dma_len -= count;
|
||||
if (s->current_dma_len == 0) {
|
||||
s->dma_buf = NULL;
|
||||
s->current->dma_len -= count;
|
||||
if (s->current->dma_len == 0) {
|
||||
s->current->dma_buf = NULL;
|
||||
if (out) {
|
||||
/* Write the data. */
|
||||
s->current_dev->info->write_data(s->current_dev, s->current_tag);
|
||||
s->current->dev->info->write_data(s->current->dev, s->current->tag);
|
||||
} else {
|
||||
/* Request any remaining data. */
|
||||
s->current_dev->info->read_data(s->current_dev, s->current_tag);
|
||||
s->current->dev->info->read_data(s->current->dev, s->current->tag);
|
||||
}
|
||||
} else {
|
||||
s->dma_buf += count;
|
||||
s->current->dma_buf += count;
|
||||
lsi_resume_script(s);
|
||||
}
|
||||
}
|
||||
@@ -563,15 +565,14 @@ static void lsi_do_dma(LSIState *s, int out)
|
||||
/* Add a command to the queue. */
|
||||
static void lsi_queue_command(LSIState *s)
|
||||
{
|
||||
lsi_queue *p;
|
||||
lsi_request *p = s->current;
|
||||
|
||||
DPRINTF("Queueing tag=0x%x\n", s->current_tag);
|
||||
if (s->queue_len == s->active_commands) {
|
||||
s->queue_len++;
|
||||
s->queue = qemu_realloc(s->queue, s->queue_len * sizeof(lsi_queue));
|
||||
}
|
||||
p = &s->queue[s->active_commands++];
|
||||
p->tag = s->current_tag;
|
||||
assert(s->current != NULL);
|
||||
assert(s->current->dma_len == 0);
|
||||
QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
|
||||
s->current = NULL;
|
||||
|
||||
p->pending = 0;
|
||||
p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
|
||||
}
|
||||
@@ -588,45 +589,29 @@ static void lsi_add_msg_byte(LSIState *s, uint8_t data)
|
||||
}
|
||||
|
||||
/* Perform reselection to continue a command. */
|
||||
static void lsi_reselect(LSIState *s, uint32_t tag)
|
||||
static void lsi_reselect(LSIState *s, lsi_request *p)
|
||||
{
|
||||
lsi_queue *p;
|
||||
int n;
|
||||
int id;
|
||||
|
||||
p = NULL;
|
||||
for (n = 0; n < s->active_commands; n++) {
|
||||
p = &s->queue[n];
|
||||
if (p->tag == tag)
|
||||
break;
|
||||
}
|
||||
if (n == s->active_commands) {
|
||||
BADF("Reselected non-existant command tag=0x%x\n", tag);
|
||||
return;
|
||||
}
|
||||
id = (tag >> 8) & 0xf;
|
||||
assert(s->current == NULL);
|
||||
QTAILQ_REMOVE(&s->queue, p, next);
|
||||
s->current = p;
|
||||
|
||||
id = (p->tag >> 8) & 0xf;
|
||||
s->ssid = id | 0x80;
|
||||
/* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
|
||||
if (!s->dcntl & LSI_DCNTL_COM) {
|
||||
s->sfbr = 1 << (id & 0x7);
|
||||
}
|
||||
DPRINTF("Reselected target %d\n", id);
|
||||
s->current_dev = s->bus.devs[id];
|
||||
s->current_tag = tag;
|
||||
s->scntl1 |= LSI_SCNTL1_CON;
|
||||
lsi_set_phase(s, PHASE_MI);
|
||||
s->msg_action = p->out ? 2 : 3;
|
||||
s->current_dma_len = p->pending;
|
||||
s->dma_buf = NULL;
|
||||
s->current->dma_len = p->pending;
|
||||
lsi_add_msg_byte(s, 0x80);
|
||||
if (s->current_tag & LSI_TAG_VALID) {
|
||||
if (s->current->tag & LSI_TAG_VALID) {
|
||||
lsi_add_msg_byte(s, 0x20);
|
||||
lsi_add_msg_byte(s, tag & 0xff);
|
||||
}
|
||||
|
||||
s->active_commands--;
|
||||
if (n != s->active_commands) {
|
||||
s->queue[n] = s->queue[s->active_commands];
|
||||
lsi_add_msg_byte(s, p->tag & 0xff);
|
||||
}
|
||||
|
||||
if (lsi_irq_on_rsl(s)) {
|
||||
@@ -638,10 +623,9 @@ static void lsi_reselect(LSIState *s, uint32_t tag)
|
||||
the device was reselected, nonzero if the IO is deferred. */
|
||||
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
|
||||
{
|
||||
lsi_queue *p;
|
||||
int i;
|
||||
for (i = 0; i < s->active_commands; i++) {
|
||||
p = &s->queue[i];
|
||||
lsi_request *p;
|
||||
|
||||
QTAILQ_FOREACH(p, &s->queue, next) {
|
||||
if (p->tag == tag) {
|
||||
if (p->pending) {
|
||||
BADF("Multiple IO pending for tag %d\n", tag);
|
||||
@@ -656,10 +640,10 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
|
||||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
|
||||
!(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
|
||||
/* Reselect device. */
|
||||
lsi_reselect(s, tag);
|
||||
lsi_reselect(s, p);
|
||||
return 0;
|
||||
} else {
|
||||
DPRINTF("Queueing IO tag=0x%x\n", tag);
|
||||
DPRINTF("Queueing IO tag=0x%x\n", tag);
|
||||
p->pending = arg;
|
||||
return 1;
|
||||
}
|
||||
@@ -687,11 +671,15 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
|
||||
} else {
|
||||
lsi_set_phase(s, PHASE_ST);
|
||||
}
|
||||
|
||||
qemu_free(s->current);
|
||||
s->current = NULL;
|
||||
|
||||
lsi_resume_script(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->waiting == 1 || tag != s->current_tag ||
|
||||
if (s->waiting == 1 || !s->current || tag != s->current->tag ||
|
||||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
|
||||
if (lsi_queue_tag(s, tag, arg))
|
||||
return;
|
||||
@@ -699,7 +687,7 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
|
||||
|
||||
/* host adapter (re)connected */
|
||||
DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);
|
||||
s->current_dma_len = arg;
|
||||
s->current->dma_len = arg;
|
||||
s->command_complete = 1;
|
||||
if (!s->waiting)
|
||||
return;
|
||||
@@ -721,14 +709,20 @@ static void lsi_do_command(LSIState *s)
|
||||
cpu_physical_memory_read(s->dnad, buf, s->dbc);
|
||||
s->sfbr = buf[0];
|
||||
s->command_complete = 0;
|
||||
n = s->current_dev->info->send_command(s->current_dev, s->current_tag, buf,
|
||||
s->current_lun);
|
||||
|
||||
assert(s->current == NULL);
|
||||
s->current = qemu_mallocz(sizeof(lsi_request));
|
||||
s->current->tag = s->select_tag;
|
||||
s->current->dev = s->select_dev;
|
||||
|
||||
n = s->current->dev->info->send_command(s->current->dev, s->current->tag, buf,
|
||||
s->current_lun);
|
||||
if (n > 0) {
|
||||
lsi_set_phase(s, PHASE_DI);
|
||||
s->current_dev->info->read_data(s->current_dev, s->current_tag);
|
||||
s->current->dev->info->read_data(s->current->dev, s->current->tag);
|
||||
} else if (n < 0) {
|
||||
lsi_set_phase(s, PHASE_DO);
|
||||
s->current_dev->info->write_data(s->current_dev, s->current_tag);
|
||||
s->current->dev->info->write_data(s->current->dev, s->current->tag);
|
||||
}
|
||||
|
||||
if (!s->command_complete) {
|
||||
@@ -851,16 +845,16 @@ static void lsi_do_msgout(LSIState *s)
|
||||
}
|
||||
break;
|
||||
case 0x20: /* SIMPLE queue */
|
||||
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||
DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff);
|
||||
break;
|
||||
case 0x21: /* HEAD of queue */
|
||||
BADF("HEAD queue not implemented\n");
|
||||
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||
break;
|
||||
case 0x22: /* ORDERED queue */
|
||||
BADF("ORDERED queue not implemented\n");
|
||||
s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
|
||||
break;
|
||||
default:
|
||||
if ((msg & 0x80) == 0) {
|
||||
@@ -905,17 +899,17 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
|
||||
|
||||
static void lsi_wait_reselect(LSIState *s)
|
||||
{
|
||||
int i;
|
||||
lsi_request *p;
|
||||
|
||||
DPRINTF("Wait Reselect\n");
|
||||
if (s->current_dma_len)
|
||||
BADF("Reselect with pending DMA\n");
|
||||
for (i = 0; i < s->active_commands; i++) {
|
||||
if (s->queue[i].pending) {
|
||||
lsi_reselect(s, s->queue[i].tag);
|
||||
|
||||
QTAILQ_FOREACH(p, &s->queue, next) {
|
||||
if (p->pending) {
|
||||
lsi_reselect(s, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s->current_dma_len == 0) {
|
||||
if (s->current == NULL) {
|
||||
s->waiting = 1;
|
||||
}
|
||||
}
|
||||
@@ -1093,8 +1087,8 @@ again:
|
||||
/* ??? Linux drivers compain when this is set. Maybe
|
||||
it only applies in low-level mode (unimplemented).
|
||||
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
|
||||
s->current_dev = s->bus.devs[id];
|
||||
s->current_tag = id << 8;
|
||||
s->select_dev = s->bus.devs[id];
|
||||
s->select_tag = id << 8;
|
||||
s->scntl1 |= LSI_SCNTL1_CON;
|
||||
if (insn & (1 << 3)) {
|
||||
s->socl |= LSI_SOCL_ATN;
|
||||
@@ -2006,9 +2000,11 @@ static void lsi_pre_save(void *opaque)
|
||||
{
|
||||
LSIState *s = opaque;
|
||||
|
||||
assert(s->dma_buf == NULL);
|
||||
assert(s->current_dma_len == 0);
|
||||
assert(s->active_commands == 0);
|
||||
if (s->current) {
|
||||
assert(s->current->dma_buf == NULL);
|
||||
assert(s->current->dma_len == 0);
|
||||
}
|
||||
assert(QTAILQ_EMPTY(&s->queue));
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_lsi_scsi = {
|
||||
@@ -2101,8 +2097,6 @@ static int lsi_scsi_uninit(PCIDevice *d)
|
||||
cpu_unregister_io_memory(s->mmio_io_addr);
|
||||
cpu_unregister_io_memory(s->ram_io_addr);
|
||||
|
||||
qemu_free(s->queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2138,9 +2132,7 @@ static int lsi_scsi_init(PCIDevice *dev)
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
|
||||
pci_register_bar((struct PCIDevice *)s, 2, 0x2000,
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
|
||||
s->queue = qemu_malloc(sizeof(lsi_queue));
|
||||
s->queue_len = 1;
|
||||
s->active_commands = 0;
|
||||
QTAILQ_INIT(&s->queue);
|
||||
|
||||
lsi_soft_reset(s);
|
||||
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@
|
||||
|
||||
//#define DEBUG_CMOS
|
||||
|
||||
#define RTC_REINJECT_ON_ACK_COUNT 1000
|
||||
#define RTC_REINJECT_ON_ACK_COUNT 20
|
||||
|
||||
#define RTC_SECONDS 0
|
||||
#define RTC_SECONDS_ALARM 1
|
||||
|
||||
+4
-5
@@ -67,7 +67,7 @@
|
||||
#define MP_AUDIO_IRQ 30
|
||||
|
||||
/* Wolfson 8750 I2C address */
|
||||
#define MP_WM_ADDR 0x34
|
||||
#define MP_WM_ADDR 0x1A
|
||||
|
||||
/* Ethernet register offsets */
|
||||
#define MP_ETH_SMIR 0x010
|
||||
@@ -238,14 +238,13 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index)
|
||||
{
|
||||
uint32_t desc_addr = s->tx_queue[queue_index];
|
||||
mv88w8618_tx_desc desc;
|
||||
uint32_t next_desc;
|
||||
uint8_t buf[2048];
|
||||
int len;
|
||||
|
||||
if (!desc_addr) {
|
||||
return;
|
||||
}
|
||||
do {
|
||||
eth_tx_desc_get(desc_addr, &desc);
|
||||
next_desc = desc.next;
|
||||
if (desc.cmdstat & MP_ETH_TX_OWN) {
|
||||
len = desc.bytes;
|
||||
if (len < 2048) {
|
||||
@@ -256,7 +255,7 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index)
|
||||
s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
|
||||
eth_tx_desc_put(desc_addr, &desc);
|
||||
}
|
||||
desc_addr = desc.next;
|
||||
desc_addr = next_desc;
|
||||
} while (desc_addr != s->tx_queue[queue_index]);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "hw.h"
|
||||
#include "pc.h"
|
||||
#include "fdc.h"
|
||||
#include "ide.h"
|
||||
#include "pci.h"
|
||||
#include "vmware_vga.h"
|
||||
#include "usb-uhci.h"
|
||||
@@ -244,15 +245,66 @@ static int pc_boot_set(void *opaque, const char *boot_device)
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* hd_table must contain 4 block drivers */
|
||||
typedef struct pc_cmos_init_late_arg {
|
||||
BusState *idebus0, *idebus1;
|
||||
} pc_cmos_init_late_arg;
|
||||
|
||||
static void pc_cmos_init_late(void *opaque)
|
||||
{
|
||||
pc_cmos_init_late_arg *arg = opaque;
|
||||
RTCState *s = rtc_state;
|
||||
int val;
|
||||
BlockDriverState *hd_table[4];
|
||||
int i;
|
||||
|
||||
ide_get_bs(hd_table, arg->idebus0);
|
||||
ide_get_bs(hd_table + 2, arg->idebus1);
|
||||
|
||||
rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
|
||||
if (hd_table[0])
|
||||
cmos_init_hd(0x19, 0x1b, hd_table[0]);
|
||||
if (hd_table[1])
|
||||
cmos_init_hd(0x1a, 0x24, hd_table[1]);
|
||||
|
||||
val = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (hd_table[i]) {
|
||||
int cylinders, heads, sectors, translation;
|
||||
/* NOTE: bdrv_get_geometry_hint() returns the physical
|
||||
geometry. It is always such that: 1 <= sects <= 63, 1
|
||||
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
|
||||
geometry can be different if a translation is done. */
|
||||
translation = bdrv_get_translation_hint(hd_table[i]);
|
||||
if (translation == BIOS_ATA_TRANSLATION_AUTO) {
|
||||
bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors);
|
||||
if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
|
||||
/* No translation. */
|
||||
translation = 0;
|
||||
} else {
|
||||
/* LBA translation. */
|
||||
translation = 1;
|
||||
}
|
||||
} else {
|
||||
translation--;
|
||||
}
|
||||
val |= translation << (i * 2);
|
||||
}
|
||||
}
|
||||
rtc_set_memory(s, 0x39, val);
|
||||
|
||||
qemu_unregister_reset(pc_cmos_init_late, opaque);
|
||||
}
|
||||
|
||||
static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
const char *boot_device, DriveInfo **hd_table)
|
||||
const char *boot_device,
|
||||
BusState *idebus0, BusState *idebus1)
|
||||
{
|
||||
RTCState *s = rtc_state;
|
||||
int nbds, bds[3] = { 0, };
|
||||
int val;
|
||||
int fd0, fd1, nb;
|
||||
int i;
|
||||
static pc_cmos_init_late_arg arg;
|
||||
|
||||
/* various important CMOS locations needed by PC/Bochs bios */
|
||||
|
||||
@@ -335,37 +387,9 @@ static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
|
||||
/* hard drives */
|
||||
|
||||
rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
|
||||
if (hd_table[0])
|
||||
cmos_init_hd(0x19, 0x1b, hd_table[0]->bdrv);
|
||||
if (hd_table[1])
|
||||
cmos_init_hd(0x1a, 0x24, hd_table[1]->bdrv);
|
||||
|
||||
val = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (hd_table[i]) {
|
||||
int cylinders, heads, sectors, translation;
|
||||
/* NOTE: bdrv_get_geometry_hint() returns the physical
|
||||
geometry. It is always such that: 1 <= sects <= 63, 1
|
||||
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
|
||||
geometry can be different if a translation is done. */
|
||||
translation = bdrv_get_translation_hint(hd_table[i]->bdrv);
|
||||
if (translation == BIOS_ATA_TRANSLATION_AUTO) {
|
||||
bdrv_get_geometry_hint(hd_table[i]->bdrv, &cylinders, &heads, §ors);
|
||||
if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
|
||||
/* No translation. */
|
||||
translation = 0;
|
||||
} else {
|
||||
/* LBA translation. */
|
||||
translation = 1;
|
||||
}
|
||||
} else {
|
||||
translation--;
|
||||
}
|
||||
val |= translation << (i * 2);
|
||||
}
|
||||
}
|
||||
rtc_set_memory(s, 0x39, val);
|
||||
arg.idebus0 = idebus0;
|
||||
arg.idebus1 = idebus1;
|
||||
qemu_register_reset(pc_cmos_init_late, &arg);
|
||||
}
|
||||
|
||||
void ioport_set_a20(int enable)
|
||||
@@ -994,6 +1018,7 @@ static void pc_init1(ram_addr_t ram_size,
|
||||
qemu_irq *i8259;
|
||||
IsaIrqState *isa_irq_state;
|
||||
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
||||
BusState *idebus[MAX_IDE_BUS];
|
||||
DriveInfo *fd[MAX_FD];
|
||||
void *fw_cfg;
|
||||
|
||||
@@ -1187,11 +1212,16 @@ static void pc_init1(ram_addr_t ram_size,
|
||||
}
|
||||
|
||||
if (pci_enabled) {
|
||||
pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
|
||||
PCIDevice *dev;
|
||||
dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
|
||||
idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
|
||||
idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
|
||||
} else {
|
||||
for(i = 0; i < MAX_IDE_BUS; i++) {
|
||||
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
|
||||
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
|
||||
ISADevice *dev;
|
||||
dev = isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
|
||||
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
|
||||
idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1206,7 +1236,8 @@ static void pc_init1(ram_addr_t ram_size,
|
||||
}
|
||||
floppy_controller = fdctrl_init_isa(fd);
|
||||
|
||||
cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd);
|
||||
cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
|
||||
idebus[0], idebus[1]);
|
||||
|
||||
if (pci_enabled && usb_enabled) {
|
||||
usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
|
||||
@@ -1306,6 +1337,14 @@ static QEMUMachine pc_machine_v0_11 = {
|
||||
.driver = "virtio-blk-pci",
|
||||
.property = "vectors",
|
||||
.value = stringify(0),
|
||||
},{
|
||||
.driver = "ide-drive",
|
||||
.property = "ver",
|
||||
.value = "0.11",
|
||||
},{
|
||||
.driver = "scsi-disk",
|
||||
.property = "ver",
|
||||
.value = "0.11",
|
||||
},{
|
||||
.driver = "PCI",
|
||||
.property = "rombar",
|
||||
@@ -1337,6 +1376,14 @@ static QEMUMachine pc_machine_v0_10 = {
|
||||
.driver = "virtio-blk-pci",
|
||||
.property = "vectors",
|
||||
.value = stringify(0),
|
||||
},{
|
||||
.driver = "ide-drive",
|
||||
.property = "ver",
|
||||
.value = "0.10",
|
||||
},{
|
||||
.driver = "scsi-disk",
|
||||
.property = "ver",
|
||||
.value = "0.10",
|
||||
},{
|
||||
.driver = "PCI",
|
||||
.property = "rombar",
|
||||
|
||||
@@ -317,7 +317,7 @@ static VMStateInfo vmstate_info_pci_config = {
|
||||
|
||||
static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
|
||||
{
|
||||
PCIDevice *s = container_of(pv, PCIDevice, config);
|
||||
PCIDevice *s = container_of(pv, PCIDevice, irq_state);
|
||||
uint32_t irq_state[PCI_NUM_PINS];
|
||||
int i;
|
||||
for (i = 0; i < PCI_NUM_PINS; ++i) {
|
||||
@@ -339,7 +339,7 @@ static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
|
||||
static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size)
|
||||
{
|
||||
int i;
|
||||
PCIDevice *s = container_of(pv, PCIDevice, config);
|
||||
PCIDevice *s = container_of(pv, PCIDevice, irq_state);
|
||||
|
||||
for (i = 0; i < PCI_NUM_PINS; ++i) {
|
||||
qemu_put_be32(f, pci_irq_state(s, i));
|
||||
|
||||
+7
-2
@@ -65,6 +65,7 @@ struct SCSIDiskState
|
||||
int cluster_size;
|
||||
uint64_t max_lba;
|
||||
QEMUBH *bh;
|
||||
char *version;
|
||||
};
|
||||
|
||||
static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
|
||||
@@ -80,7 +81,7 @@ static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
|
||||
|
||||
static void scsi_remove_request(SCSIDiskReq *r)
|
||||
{
|
||||
qemu_free(r->iov.iov_base);
|
||||
qemu_vfree(r->iov.iov_base);
|
||||
scsi_req_free(&r->req);
|
||||
}
|
||||
|
||||
@@ -315,6 +316,7 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
|
||||
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
||||
{
|
||||
BlockDriverState *bdrv = req->dev->dinfo->bdrv;
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||
int buflen = 0;
|
||||
|
||||
if (req->cmd.buf[1] & 0x2) {
|
||||
@@ -432,7 +434,9 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
||||
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
|
||||
}
|
||||
memcpy(&outbuf[8], "QEMU ", 8);
|
||||
memcpy(&outbuf[32], QEMU_VERSION, 4);
|
||||
memset(&outbuf[32], 0, 4);
|
||||
memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION,
|
||||
MIN(4, strlen(s->version ? s->version : QEMU_VERSION)));
|
||||
/* Identify device as SCSI-3 rev 1.
|
||||
Some later commands are also implemented. */
|
||||
outbuf[2] = 3;
|
||||
@@ -1029,6 +1033,7 @@ static SCSIDeviceInfo scsi_disk_info = {
|
||||
.get_buf = scsi_get_buf,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.dinfo),
|
||||
DEFINE_PROP_STRING("ver", SCSIDiskState, version),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
+5
-2
@@ -396,8 +396,11 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr,
|
||||
portb_changed(s, temp);
|
||||
return;
|
||||
case SH7750_MMUCR_A7:
|
||||
s->cpu->mmucr = mem_value;
|
||||
return;
|
||||
if (mem_value & MMUCR_TI) {
|
||||
cpu_sh4_invalidate_tlb(s->cpu);
|
||||
}
|
||||
s->cpu->mmucr = mem_value & ~MMUCR_TI;
|
||||
return;
|
||||
case SH7750_PTEH_A7:
|
||||
/* If asid changes, clear all registered tlb entries. */
|
||||
if ((s->cpu->pteh & 0xff) != (mem_value & 0xff))
|
||||
|
||||
+15
-96
@@ -47,10 +47,15 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
|
||||
pcic->par = val;
|
||||
break;
|
||||
case 0x1c4:
|
||||
pcic->mbr = val;
|
||||
pcic->mbr = val & 0xff000001;
|
||||
break;
|
||||
case 0x1c8:
|
||||
pcic->iobr = val;
|
||||
if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) {
|
||||
cpu_register_physical_memory(pcic->iobr & 0xfffc0000, 0x40000,
|
||||
IO_MEM_UNASSIGNED);
|
||||
pcic->iobr = val & 0xfffc0001;
|
||||
isa_mmio_init(pcic->iobr & 0xfffc0000, 0x40000);
|
||||
}
|
||||
break;
|
||||
case 0x220:
|
||||
pci_data_write(pcic->bus, pcic->par, val, 4);
|
||||
@@ -66,89 +71,16 @@ static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr)
|
||||
return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
|
||||
case 0x1c0:
|
||||
return pcic->par;
|
||||
case 0x1c4:
|
||||
return pcic->mbr;
|
||||
case 0x1c8:
|
||||
return pcic->iobr;
|
||||
case 0x220:
|
||||
return pci_data_read(pcic->bus, pcic->par, 4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_pci_data_write (SHPCIC *pcic, target_phys_addr_t addr,
|
||||
uint32_t val, int size)
|
||||
{
|
||||
pci_data_write(pcic->bus, addr + pcic->mbr, val, size);
|
||||
}
|
||||
|
||||
static uint32_t sh_pci_mem_read (SHPCIC *pcic, target_phys_addr_t addr,
|
||||
int size)
|
||||
{
|
||||
return pci_data_read(pcic->bus, addr + pcic->mbr, size);
|
||||
}
|
||||
|
||||
static void sh_pci_writeb (void *p, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
sh_pci_data_write(p, addr, val, 1);
|
||||
}
|
||||
|
||||
static void sh_pci_writew (void *p, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
sh_pci_data_write(p, addr, val, 2);
|
||||
}
|
||||
|
||||
static void sh_pci_writel (void *p, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
sh_pci_data_write(p, addr, val, 4);
|
||||
}
|
||||
|
||||
static uint32_t sh_pci_readb (void *p, target_phys_addr_t addr)
|
||||
{
|
||||
return sh_pci_mem_read(p, addr, 1);
|
||||
}
|
||||
|
||||
static uint32_t sh_pci_readw (void *p, target_phys_addr_t addr)
|
||||
{
|
||||
return sh_pci_mem_read(p, addr, 2);
|
||||
}
|
||||
|
||||
static uint32_t sh_pci_readl (void *p, target_phys_addr_t addr)
|
||||
{
|
||||
return sh_pci_mem_read(p, addr, 4);
|
||||
}
|
||||
|
||||
static int sh_pci_addr2port(SHPCIC *pcic, target_phys_addr_t addr)
|
||||
{
|
||||
return addr + pcic->iobr;
|
||||
}
|
||||
|
||||
static void sh_pci_outb (void *p, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
cpu_outb(sh_pci_addr2port(p, addr), val);
|
||||
}
|
||||
|
||||
static void sh_pci_outw (void *p, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
cpu_outw(sh_pci_addr2port(p, addr), val);
|
||||
}
|
||||
|
||||
static void sh_pci_outl (void *p, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
cpu_outl(sh_pci_addr2port(p, addr), val);
|
||||
}
|
||||
|
||||
static uint32_t sh_pci_inb (void *p, target_phys_addr_t addr)
|
||||
{
|
||||
return cpu_inb(sh_pci_addr2port(p, addr));
|
||||
}
|
||||
|
||||
static uint32_t sh_pci_inw (void *p, target_phys_addr_t addr)
|
||||
{
|
||||
return cpu_inw(sh_pci_addr2port(p, addr));
|
||||
}
|
||||
|
||||
static uint32_t sh_pci_inl (void *p, target_phys_addr_t addr)
|
||||
{
|
||||
return cpu_inl(sh_pci_addr2port(p, addr));
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
CPUReadMemoryFunc * const r[3];
|
||||
CPUWriteMemoryFunc * const w[3];
|
||||
@@ -159,21 +91,11 @@ static MemOp sh_pci_reg = {
|
||||
{ NULL, NULL, sh_pci_reg_write },
|
||||
};
|
||||
|
||||
static MemOp sh_pci_mem = {
|
||||
{ sh_pci_readb, sh_pci_readw, sh_pci_readl },
|
||||
{ sh_pci_writeb, sh_pci_writew, sh_pci_writel },
|
||||
};
|
||||
|
||||
static MemOp sh_pci_iop = {
|
||||
{ sh_pci_inb, sh_pci_inw, sh_pci_inl },
|
||||
{ sh_pci_outb, sh_pci_outw, sh_pci_outl },
|
||||
};
|
||||
|
||||
PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
|
||||
void *opaque, int devfn_min, int nirq)
|
||||
{
|
||||
SHPCIC *p;
|
||||
int mem, reg, iop;
|
||||
int reg;
|
||||
|
||||
p = qemu_mallocz(sizeof(SHPCIC));
|
||||
p->bus = pci_register_bus(NULL, "pci",
|
||||
@@ -182,14 +104,11 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
|
||||
p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
|
||||
-1, NULL, NULL);
|
||||
reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p);
|
||||
iop = cpu_register_io_memory(sh_pci_iop.r, sh_pci_iop.w, p);
|
||||
mem = cpu_register_io_memory(sh_pci_mem.r, sh_pci_mem.w, p);
|
||||
cpu_register_physical_memory(0x1e200000, 0x224, reg);
|
||||
cpu_register_physical_memory(0x1e240000, 0x40000, iop);
|
||||
cpu_register_physical_memory(0x1d000000, 0x1000000, mem);
|
||||
cpu_register_physical_memory(0xfe200000, 0x224, reg);
|
||||
cpu_register_physical_memory(0xfe240000, 0x40000, iop);
|
||||
cpu_register_physical_memory(0xfd000000, 0x1000000, mem);
|
||||
|
||||
p->iobr = 0xfe240000;
|
||||
isa_mmio_init(p->iobr, 0x40000);
|
||||
|
||||
pci_config_set_vendor_id(p->dev->config, PCI_VENDOR_ID_HITACHI);
|
||||
pci_config_set_device_id(p->dev->config, PCI_DEVICE_ID_HITACHI_SH7751R);
|
||||
|
||||
+7
-2
@@ -102,6 +102,9 @@ USBDevice *usb_create(USBBus *bus, const char *name)
|
||||
USBDevice *usb_create_simple(USBBus *bus, const char *name)
|
||||
{
|
||||
USBDevice *dev = usb_create(bus, name);
|
||||
if (!dev) {
|
||||
hw_error("Failed to create USB device '%s'\n", name);
|
||||
}
|
||||
qdev_init_nofail(&dev->qdev);
|
||||
return dev;
|
||||
}
|
||||
@@ -261,7 +264,8 @@ USBDevice *usbdevice_create(const char *cmdline)
|
||||
USBBus *bus = usb_bus_find(-1 /* any */);
|
||||
DeviceInfo *info;
|
||||
USBDeviceInfo *usb;
|
||||
char driver[32], *params;
|
||||
char driver[32];
|
||||
const char *params;
|
||||
int len;
|
||||
|
||||
params = strchr(cmdline,':');
|
||||
@@ -272,6 +276,7 @@ USBDevice *usbdevice_create(const char *cmdline)
|
||||
len = sizeof(driver);
|
||||
pstrcpy(driver, len, cmdline);
|
||||
} else {
|
||||
params = "";
|
||||
pstrcpy(driver, sizeof(driver), cmdline);
|
||||
}
|
||||
|
||||
@@ -294,7 +299,7 @@ USBDevice *usbdevice_create(const char *cmdline)
|
||||
}
|
||||
|
||||
if (!usb->usbdevice_init) {
|
||||
if (params) {
|
||||
if (*params) {
|
||||
qemu_error("usbdevice %s accepts no params\n", driver);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -592,6 +592,9 @@ static USBDevice *usb_msd_init(const char *filename)
|
||||
|
||||
/* create guest device */
|
||||
dev = usb_create(NULL /* FIXME */, "usb-storage");
|
||||
if (!dev) {
|
||||
return NULL;
|
||||
}
|
||||
qdev_prop_set_drive(&dev->qdev, "drive", dinfo);
|
||||
if (qdev_init(&dev->qdev) < 0)
|
||||
return NULL;
|
||||
|
||||
+4
-1
@@ -1491,8 +1491,11 @@ static USBDevice *usb_net_init(const char *cmdline)
|
||||
}
|
||||
|
||||
dev = usb_create(NULL /* FIXME */, "usb-net");
|
||||
if (!dev) {
|
||||
return NULL;
|
||||
}
|
||||
qdev_set_nic_properties(&dev->qdev, &nd_table[idx]);
|
||||
qdev_init(&dev->qdev);
|
||||
qdev_init_nofail(&dev->qdev);
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
+27
-8
@@ -497,12 +497,28 @@ static int usb_serial_can_read(void *opaque)
|
||||
static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
USBSerialState *s = opaque;
|
||||
int first_size = RECV_BUF - s->recv_ptr;
|
||||
if (first_size > size)
|
||||
first_size = size;
|
||||
memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size);
|
||||
if (size > first_size)
|
||||
memcpy(s->recv_buf, buf + first_size, size - first_size);
|
||||
int first_size, start;
|
||||
|
||||
/* room in the buffer? */
|
||||
if (size > (RECV_BUF - s->recv_used))
|
||||
size = RECV_BUF - s->recv_used;
|
||||
|
||||
start = s->recv_ptr + s->recv_used;
|
||||
if (start < RECV_BUF) {
|
||||
/* copy data to end of buffer */
|
||||
first_size = RECV_BUF - start;
|
||||
if (first_size > size)
|
||||
first_size = size;
|
||||
|
||||
memcpy(s->recv_buf + start, buf, first_size);
|
||||
|
||||
/* wrap around to front if needed */
|
||||
if (size > first_size)
|
||||
memcpy(s->recv_buf, buf + first_size, size - first_size);
|
||||
} else {
|
||||
start -= RECV_BUF;
|
||||
memcpy(s->recv_buf + start, buf, size);
|
||||
}
|
||||
s->recv_used += size;
|
||||
}
|
||||
|
||||
@@ -578,12 +594,15 @@ static USBDevice *usb_serial_init(const char *filename)
|
||||
return NULL;
|
||||
|
||||
dev = usb_create(NULL /* FIXME */, "usb-serial");
|
||||
if (!dev) {
|
||||
return NULL;
|
||||
}
|
||||
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
|
||||
if (vendorid)
|
||||
qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);
|
||||
if (productid)
|
||||
qdev_prop_set_uint16(&dev->qdev, "productid", productid);
|
||||
qdev_init(&dev->qdev);
|
||||
qdev_init_nofail(&dev->qdev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
@@ -599,7 +618,7 @@ static USBDevice *usb_braille_init(const char *unused)
|
||||
|
||||
dev = usb_create(NULL /* FIXME */, "usb-braille");
|
||||
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
|
||||
qdev_init(&dev->qdev);
|
||||
qdev_init_nofail(&dev->qdev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
+4
-3
@@ -677,9 +677,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
|
||||
|
||||
ret = async->packet.len;
|
||||
|
||||
if (td->ctrl & TD_CTRL_IOC)
|
||||
*int_mask |= 0x01;
|
||||
|
||||
if (td->ctrl & TD_CTRL_IOS)
|
||||
td->ctrl &= ~TD_CTRL_ACTIVE;
|
||||
|
||||
@@ -693,6 +690,8 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
|
||||
here. The docs are somewhat unclear, but win2k relies on this
|
||||
behavior. */
|
||||
td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
|
||||
if (td->ctrl & TD_CTRL_IOC)
|
||||
*int_mask |= 0x01;
|
||||
|
||||
if (pid == USB_TOKEN_IN) {
|
||||
if (len > max_len) {
|
||||
@@ -750,6 +749,8 @@ out:
|
||||
if (err == 0) {
|
||||
td->ctrl &= ~TD_CTRL_ACTIVE;
|
||||
s->status |= UHCI_STS_USBERR;
|
||||
if (td->ctrl & TD_CTRL_IOC)
|
||||
*int_mask |= 0x01;
|
||||
uhci_update_irq(s);
|
||||
}
|
||||
}
|
||||
|
||||
+69
-37
@@ -272,16 +272,26 @@ static void do_multiwrite(BlockDriverState *bs, BlockRequest *blkreq,
|
||||
if (ret != 0) {
|
||||
for (i = 0; i < num_writes; i++) {
|
||||
if (blkreq[i].error) {
|
||||
virtio_blk_req_complete(blkreq[i].opaque, VIRTIO_BLK_S_IOERR);
|
||||
virtio_blk_rw_complete(blkreq[i].opaque, -EIO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_blk_handle_flush(VirtIOBlockReq *req)
|
||||
static void virtio_blk_handle_flush(BlockRequest *blkreq, int *num_writes,
|
||||
VirtIOBlockReq *req, BlockDriverState **old_bs)
|
||||
{
|
||||
BlockDriverAIOCB *acb;
|
||||
|
||||
/*
|
||||
* Make sure all outstanding writes are posted to the backing device.
|
||||
*/
|
||||
if (*old_bs != NULL) {
|
||||
do_multiwrite(*old_bs, blkreq, *num_writes);
|
||||
}
|
||||
*num_writes = 0;
|
||||
*old_bs = req->dev->bs;
|
||||
|
||||
acb = bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
|
||||
if (!acb) {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
||||
@@ -316,7 +326,47 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
|
||||
acb = bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
|
||||
req->qiov.size / 512, virtio_blk_rw_complete, req);
|
||||
if (!acb) {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
||||
virtio_blk_rw_complete(req, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct MultiReqBuffer {
|
||||
BlockRequest blkreq[32];
|
||||
int num_writes;
|
||||
BlockDriverState *old_bs;
|
||||
} MultiReqBuffer;
|
||||
|
||||
static void virtio_blk_handle_request(VirtIOBlockReq *req,
|
||||
MultiReqBuffer *mrb)
|
||||
{
|
||||
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
|
||||
fprintf(stderr, "virtio-blk missing headers\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
|
||||
req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
|
||||
fprintf(stderr, "virtio-blk header not in correct element\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
req->out = (void *)req->elem.out_sg[0].iov_base;
|
||||
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
|
||||
|
||||
if (req->out->type & VIRTIO_BLK_T_FLUSH) {
|
||||
virtio_blk_handle_flush(mrb->blkreq, &mrb->num_writes,
|
||||
req, &mrb->old_bs);
|
||||
} else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
|
||||
virtio_blk_handle_scsi(req);
|
||||
} else if (req->out->type & VIRTIO_BLK_T_OUT) {
|
||||
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
|
||||
req->elem.out_num - 1);
|
||||
virtio_blk_handle_write(mrb->blkreq, &mrb->num_writes,
|
||||
req, &mrb->old_bs);
|
||||
} else {
|
||||
qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
|
||||
req->elem.in_num - 1);
|
||||
virtio_blk_handle_read(req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,42 +374,17 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
VirtIOBlock *s = to_virtio_blk(vdev);
|
||||
VirtIOBlockReq *req;
|
||||
BlockRequest blkreq[32];
|
||||
int num_writes = 0;
|
||||
BlockDriverState *old_bs = NULL;
|
||||
MultiReqBuffer mrb = {
|
||||
.num_writes = 0,
|
||||
.old_bs = NULL,
|
||||
};
|
||||
|
||||
while ((req = virtio_blk_get_request(s))) {
|
||||
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
|
||||
fprintf(stderr, "virtio-blk missing headers\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
|
||||
req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
|
||||
fprintf(stderr, "virtio-blk header not in correct element\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
req->out = (void *)req->elem.out_sg[0].iov_base;
|
||||
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
|
||||
|
||||
if (req->out->type & VIRTIO_BLK_T_FLUSH) {
|
||||
virtio_blk_handle_flush(req);
|
||||
} else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
|
||||
virtio_blk_handle_scsi(req);
|
||||
} else if (req->out->type & VIRTIO_BLK_T_OUT) {
|
||||
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
|
||||
req->elem.out_num - 1);
|
||||
virtio_blk_handle_write(blkreq, &num_writes, req, &old_bs);
|
||||
} else {
|
||||
qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
|
||||
req->elem.in_num - 1);
|
||||
virtio_blk_handle_read(req);
|
||||
}
|
||||
virtio_blk_handle_request(req, &mrb);
|
||||
}
|
||||
|
||||
if (num_writes > 0) {
|
||||
do_multiwrite(old_bs, blkreq, num_writes);
|
||||
if (mrb.num_writes > 0) {
|
||||
do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -373,6 +398,10 @@ static void virtio_blk_dma_restart_bh(void *opaque)
|
||||
{
|
||||
VirtIOBlock *s = opaque;
|
||||
VirtIOBlockReq *req = s->rq;
|
||||
MultiReqBuffer mrb = {
|
||||
.num_writes = 0,
|
||||
.old_bs = NULL,
|
||||
};
|
||||
|
||||
qemu_bh_delete(s->bh);
|
||||
s->bh = NULL;
|
||||
@@ -380,10 +409,13 @@ static void virtio_blk_dma_restart_bh(void *opaque)
|
||||
s->rq = NULL;
|
||||
|
||||
while (req) {
|
||||
bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
|
||||
req->qiov.size / 512, virtio_blk_rw_complete, req);
|
||||
virtio_blk_handle_request(req, &mrb);
|
||||
req = req->next;
|
||||
}
|
||||
|
||||
if (mrb.num_writes > 0) {
|
||||
do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
|
||||
|
||||
+9
-1
@@ -384,7 +384,15 @@ static int virtio_net_has_buffers(VirtIONet *n, int bufsize)
|
||||
(n->mergeable_rx_bufs &&
|
||||
!virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) {
|
||||
virtio_queue_set_notification(n->rx_vq, 1);
|
||||
return 0;
|
||||
|
||||
/* To avoid a race condition where the guest has made some buffers
|
||||
* available after the above check but before notification was
|
||||
* enabled, check for available buffers again.
|
||||
*/
|
||||
if (virtio_queue_empty(n->rx_vq) ||
|
||||
(n->mergeable_rx_bufs &&
|
||||
!virtqueue_avail_bytes(n->rx_vq, bufsize, 0)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtio_queue_set_notification(n->rx_vq, 0);
|
||||
|
||||
@@ -39,8 +39,20 @@ SECTIONS
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.bss : { *(.rel.bss) }
|
||||
.rela.bss : { *(.rela.bss) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.rel.plt :
|
||||
{
|
||||
*(.rel.plt)
|
||||
PROVIDE_HIDDEN (__rel_iplt_start = .);
|
||||
*(.rel.iplt)
|
||||
PROVIDE_HIDDEN (__rel_iplt_end = .);
|
||||
}
|
||||
.rela.plt :
|
||||
{
|
||||
*(.rela.plt)
|
||||
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||
*(.rela.iplt)
|
||||
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||
}
|
||||
.init : { *(.init) } =0x47ff041f
|
||||
.text :
|
||||
{
|
||||
|
||||
@@ -54,6 +54,9 @@ enum json_lexer_state {
|
||||
IN_ESCAPE,
|
||||
IN_ESCAPE_L,
|
||||
IN_ESCAPE_LL,
|
||||
IN_ESCAPE_I,
|
||||
IN_ESCAPE_I6,
|
||||
IN_ESCAPE_I64,
|
||||
IN_ESCAPE_DONE,
|
||||
IN_WHITESPACE,
|
||||
IN_OPERATOR_DONE,
|
||||
@@ -223,6 +226,18 @@ static const uint8_t json_lexer[][256] = {
|
||||
['l'] = IN_ESCAPE_LL,
|
||||
},
|
||||
|
||||
[IN_ESCAPE_I64] = {
|
||||
['d'] = IN_ESCAPE_DONE,
|
||||
},
|
||||
|
||||
[IN_ESCAPE_I6] = {
|
||||
['4'] = IN_ESCAPE_I64,
|
||||
},
|
||||
|
||||
[IN_ESCAPE_I] = {
|
||||
['6'] = IN_ESCAPE_I6,
|
||||
},
|
||||
|
||||
[IN_ESCAPE] = {
|
||||
['d'] = IN_ESCAPE_DONE,
|
||||
['i'] = IN_ESCAPE_DONE,
|
||||
@@ -230,6 +245,7 @@ static const uint8_t json_lexer[][256] = {
|
||||
['s'] = IN_ESCAPE_DONE,
|
||||
['f'] = IN_ESCAPE_DONE,
|
||||
['l'] = IN_ESCAPE_L,
|
||||
['I'] = IN_ESCAPE_I,
|
||||
},
|
||||
|
||||
/* top level rule */
|
||||
|
||||
+3
-2
@@ -266,7 +266,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
|
||||
|
||||
peek = qlist_peek(working);
|
||||
key = parse_value(ctxt, &working, ap);
|
||||
if (qobject_type(key) != QTYPE_QSTRING) {
|
||||
if (!key || qobject_type(key) != QTYPE_QSTRING) {
|
||||
parse_error(ctxt, peek, "key is not a string in object");
|
||||
goto out;
|
||||
}
|
||||
@@ -476,7 +476,8 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a
|
||||
obj = QOBJECT(qint_from_int(va_arg(*ap, int)));
|
||||
} else if (token_is_escape(token, "%ld")) {
|
||||
obj = QOBJECT(qint_from_int(va_arg(*ap, long)));
|
||||
} else if (token_is_escape(token, "%lld")) {
|
||||
} else if (token_is_escape(token, "%lld") ||
|
||||
token_is_escape(token, "%I64d")) {
|
||||
obj = QOBJECT(qint_from_int(va_arg(*ap, long long)));
|
||||
} else if (token_is_escape(token, "%s")) {
|
||||
obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
|
||||
|
||||
+1
-1
@@ -2684,7 +2684,7 @@ int main(int argc, char **argv, char **envp)
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
#ifdef TARGET_PPC64
|
||||
cpu_model = "970";
|
||||
cpu_model = "970fx";
|
||||
#else
|
||||
cpu_model = "750";
|
||||
#endif
|
||||
|
||||
@@ -334,13 +334,10 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
|
||||
{
|
||||
QDict *qmp;
|
||||
const char *event_name;
|
||||
Monitor *mon = cur_mon;
|
||||
Monitor *mon;
|
||||
|
||||
assert(event < QEVENT_MAX);
|
||||
|
||||
if (!monitor_ctrl_mode(mon))
|
||||
return;
|
||||
|
||||
switch (event) {
|
||||
case QEVENT_DEBUG:
|
||||
event_name = "DEBUG";
|
||||
@@ -370,7 +367,11 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
|
||||
qdict_put_obj(qmp, "data", data);
|
||||
}
|
||||
|
||||
monitor_json_emitter(mon, QOBJECT(qmp));
|
||||
QLIST_FOREACH(mon, &mon_list, entry) {
|
||||
if (monitor_ctrl_mode(mon)) {
|
||||
monitor_json_emitter(mon, QOBJECT(qmp));
|
||||
}
|
||||
}
|
||||
QDECREF(qmp);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ int parse_host_src_port(struct sockaddr_in *haddr,
|
||||
struct sockaddr_in *saddr,
|
||||
const char *input_str)
|
||||
{
|
||||
char *str = strdup(input_str);
|
||||
char *str = qemu_strdup(input_str);
|
||||
char *host_str = str;
|
||||
char *src_str;
|
||||
const char *src_str2;
|
||||
@@ -812,9 +812,6 @@ static int net_init_nic(QemuOpts *opts,
|
||||
}
|
||||
|
||||
nd->used = 1;
|
||||
if (vlan) {
|
||||
nd->vlan->nb_guest_devs++;
|
||||
}
|
||||
nb_nics++;
|
||||
|
||||
return idx;
|
||||
@@ -1128,20 +1125,6 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
|
||||
return -1;
|
||||
}
|
||||
|
||||
void net_client_uninit(NICInfo *nd)
|
||||
{
|
||||
if (nd->vlan) {
|
||||
nd->vlan->nb_guest_devs--;
|
||||
}
|
||||
nb_nics--;
|
||||
|
||||
qemu_free(nd->model);
|
||||
qemu_free(nd->name);
|
||||
qemu_free(nd->devaddr);
|
||||
|
||||
nd->used = 0;
|
||||
}
|
||||
|
||||
static int net_host_check_device(const char *device)
|
||||
{
|
||||
int i;
|
||||
@@ -1204,39 +1187,26 @@ void net_host_device_remove(Monitor *mon, const QDict *qdict)
|
||||
qemu_del_vlan_client(vc);
|
||||
}
|
||||
|
||||
void net_set_boot_mask(int net_boot_mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Only the first four NICs may be bootable */
|
||||
net_boot_mask = net_boot_mask & 0xF;
|
||||
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
if (net_boot_mask & (1 << i)) {
|
||||
nd_table[i].bootable = 1;
|
||||
net_boot_mask &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (net_boot_mask) {
|
||||
fprintf(stderr, "Cannot boot from non-existent NIC\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void do_info_network(Monitor *mon)
|
||||
{
|
||||
VLANState *vlan;
|
||||
VLANClientState *vc;
|
||||
|
||||
QTAILQ_FOREACH(vlan, &vlans, next) {
|
||||
VLANClientState *vc;
|
||||
|
||||
monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
|
||||
|
||||
QTAILQ_FOREACH(vc, &vlan->clients, next) {
|
||||
monitor_printf(mon, " %s: %s\n", vc->name, vc->info_str);
|
||||
}
|
||||
}
|
||||
monitor_printf(mon, "Devices not on any VLAN:\n");
|
||||
QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
|
||||
monitor_printf(mon, " %s: %s", vc->name, vc->info_str);
|
||||
if (vc->peer) {
|
||||
monitor_printf(mon, " peer=%s", vc->peer->name);
|
||||
}
|
||||
monitor_printf(mon, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void do_set_link(Monitor *mon, const QDict *qdict)
|
||||
@@ -1253,6 +1223,7 @@ void do_set_link(Monitor *mon, const QDict *qdict)
|
||||
}
|
||||
}
|
||||
}
|
||||
vc = qemu_find_netdev(name);
|
||||
done:
|
||||
|
||||
if (!vc) {
|
||||
@@ -1289,20 +1260,41 @@ void net_cleanup(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void net_check_clients(void)
|
||||
void net_check_clients(void)
|
||||
{
|
||||
VLANState *vlan;
|
||||
VLANClientState *vc;
|
||||
int has_nic, has_host_dev;
|
||||
|
||||
QTAILQ_FOREACH(vlan, &vlans, next) {
|
||||
if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
|
||||
continue;
|
||||
if (vlan->nb_guest_devs == 0)
|
||||
QTAILQ_FOREACH(vc, &vlan->clients, next) {
|
||||
switch (vc->info->type) {
|
||||
case NET_CLIENT_TYPE_NIC:
|
||||
has_nic = 1;
|
||||
break;
|
||||
case NET_CLIENT_TYPE_SLIRP:
|
||||
case NET_CLIENT_TYPE_TAP:
|
||||
case NET_CLIENT_TYPE_SOCKET:
|
||||
case NET_CLIENT_TYPE_VDE:
|
||||
has_host_dev = 1;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
if (has_host_dev && !has_nic)
|
||||
fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
|
||||
if (vlan->nb_host_devs == 0)
|
||||
if (has_nic && !has_host_dev)
|
||||
fprintf(stderr,
|
||||
"Warning: vlan %d is not connected to host network\n",
|
||||
vlan->id);
|
||||
}
|
||||
QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
|
||||
if (!vc->peer) {
|
||||
fprintf(stderr, "Warning: %s %s has no peer\n",
|
||||
vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev",
|
||||
vc->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int net_init_client(QemuOpts *opts, void *dummy)
|
||||
@@ -1337,8 +1329,6 @@ int net_init_clients(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_check_clients();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ struct VLANState {
|
||||
int id;
|
||||
QTAILQ_HEAD(, VLANClientState) clients;
|
||||
QTAILQ_ENTRY(VLANState) next;
|
||||
unsigned int nb_guest_devs, nb_host_devs;
|
||||
NetQueue *send_queue;
|
||||
};
|
||||
|
||||
@@ -160,11 +159,10 @@ extern const char *legacy_tftp_prefix;
|
||||
extern const char *legacy_bootp_filename;
|
||||
|
||||
int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev);
|
||||
void net_client_uninit(NICInfo *nd);
|
||||
int net_client_parse(QemuOptsList *opts_list, const char *str);
|
||||
int net_init_clients(void);
|
||||
void net_check_clients(void);
|
||||
void net_cleanup(void);
|
||||
void net_set_boot_mask(int boot_mask);
|
||||
void net_host_device_add(Monitor *mon, const QDict *qdict);
|
||||
void net_host_device_remove(Monitor *mon, const QDict *qdict);
|
||||
|
||||
|
||||
@@ -728,10 +728,6 @@ int net_init_slirp(QemuOpts *opts,
|
||||
qemu_free(config);
|
||||
}
|
||||
|
||||
if (ret != -1 && vlan) {
|
||||
vlan->nb_host_devs++;
|
||||
}
|
||||
|
||||
qemu_free(vnet);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -569,9 +569,5 @@ int net_init_socket(QemuOpts *opts,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vlan) {
|
||||
vlan->nb_host_devs++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -714,10 +714,6 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vlan) {
|
||||
vlan->nb_host_devs++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -441,9 +441,5 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
|
||||
}
|
||||
}
|
||||
|
||||
if (vlan) {
|
||||
vlan->nb_host_devs++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -127,9 +127,5 @@ int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vlan) {
|
||||
vlan->nb_host_devs++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -106,10 +106,10 @@ copy_kernel:
|
||||
/* We're now running in 16-bit CS, but 32-bit ES! */
|
||||
|
||||
/* Load kernel and initrd */
|
||||
read_fw_blob(FW_CFG_KERNEL)
|
||||
read_fw_blob(FW_CFG_INITRD)
|
||||
read_fw_blob(FW_CFG_CMDLINE)
|
||||
read_fw_blob(FW_CFG_SETUP)
|
||||
read_fw_blob_addr32(FW_CFG_KERNEL)
|
||||
read_fw_blob_addr32(FW_CFG_INITRD)
|
||||
read_fw_blob_addr32(FW_CFG_CMDLINE)
|
||||
read_fw_blob_addr32(FW_CFG_SETUP)
|
||||
|
||||
/* And now jump into Linux! */
|
||||
mov $0, %eax
|
||||
|
||||
@@ -50,13 +50,7 @@
|
||||
bswap %eax
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Read a blob from the fw_cfg device.
|
||||
* Requires _ADDR, _SIZE and _DATA values for the parameter.
|
||||
*
|
||||
* Clobbers: %eax, %edx, %es, %ecx, %edi
|
||||
*/
|
||||
#define read_fw_blob(var) \
|
||||
#define read_fw_blob_pre(var) \
|
||||
read_fw var ## _ADDR; \
|
||||
mov %eax, %edi; \
|
||||
read_fw var ## _SIZE; \
|
||||
@@ -65,10 +59,32 @@
|
||||
mov $BIOS_CFG_IOPORT_CFG, %edx; \
|
||||
outw %ax, (%dx); \
|
||||
mov $BIOS_CFG_IOPORT_DATA, %dx; \
|
||||
cld; \
|
||||
cld
|
||||
|
||||
/*
|
||||
* Read a blob from the fw_cfg device.
|
||||
* Requires _ADDR, _SIZE and _DATA values for the parameter.
|
||||
*
|
||||
* Clobbers: %eax, %edx, %es, %ecx, %edi
|
||||
*/
|
||||
#define read_fw_blob(var) \
|
||||
read_fw_blob_pre(var); \
|
||||
/* old as(1) doesn't like this insn so emit the bytes instead: \
|
||||
rep insb (%dx), %es:(%edi); \
|
||||
*/ \
|
||||
.dc.b 0xf3,0x6c
|
||||
|
||||
/*
|
||||
* Read a blob from the fw_cfg device in forced addr32 mode.
|
||||
* Requires _ADDR, _SIZE and _DATA values for the parameter.
|
||||
*
|
||||
* Clobbers: %eax, %edx, %es, %ecx, %edi
|
||||
*/
|
||||
#define read_fw_blob_addr32(var) \
|
||||
read_fw_blob_pre(var); \
|
||||
/* old as(1) doesn't like this insn so emit the bytes instead: \
|
||||
addr32 rep insb (%dx), %es:(%edi); \
|
||||
*/ \
|
||||
.dc.b 0x67,0xf3,0x6c
|
||||
|
||||
#define OPTION_ROM_START \
|
||||
|
||||
+4
-4
@@ -1180,6 +1180,9 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
|
||||
int fd;
|
||||
|
||||
TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
tty_serial_init(fd, 115200, 'N', 8, 1);
|
||||
chr = qemu_chr_open_fd(fd, fd);
|
||||
if (!chr) {
|
||||
@@ -2314,8 +2317,7 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
|
||||
qemu_opt_set(opts, "backend", "udp");
|
||||
if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) {
|
||||
host[0] = 0;
|
||||
if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
|
||||
fprintf(stderr, "udp #1\n");
|
||||
if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -2326,7 +2328,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
|
||||
if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
|
||||
host[0] = 0;
|
||||
if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
|
||||
fprintf(stderr, "udp #2\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -2354,7 +2355,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
|
||||
}
|
||||
|
||||
fail:
|
||||
fprintf(stderr, "%s: fail on \"%s\"\n", __FUNCTION__, filename);
|
||||
qemu_opts_del(opts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+6
-1
@@ -2,6 +2,8 @@
|
||||
#ifndef QEMU_COMMON_H
|
||||
#define QEMU_COMMON_H
|
||||
|
||||
#include "config-host.h"
|
||||
|
||||
#define QEMU_NORETURN __attribute__ ((__noreturn__))
|
||||
#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT
|
||||
#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
@@ -29,7 +31,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
#include "config-host.h"
|
||||
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
@@ -53,6 +54,10 @@ struct iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
/*
|
||||
* Use the same value as Linux for now.
|
||||
*/
|
||||
#define IOV_MAX 1024
|
||||
#else
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -537,7 +537,7 @@ static int img_convert(int argc, char **argv)
|
||||
BlockDriverState **bs, *out_bs;
|
||||
int64_t total_sectors, nb_sectors, sector_num, bs_offset;
|
||||
uint64_t bs_sectors;
|
||||
uint8_t buf[IO_BUF_SIZE];
|
||||
uint8_t * buf;
|
||||
const uint8_t *buf1;
|
||||
BlockDriverInfo bdi;
|
||||
QEMUOptionParameter *param = NULL;
|
||||
@@ -656,6 +656,7 @@ static int img_convert(int argc, char **argv)
|
||||
bs_i = 0;
|
||||
bs_offset = 0;
|
||||
bdrv_get_geometry(bs[0], &bs_sectors);
|
||||
buf = qemu_malloc(IO_BUF_SIZE);
|
||||
|
||||
if (flags & BLOCK_FLAG_COMPRESS) {
|
||||
if (bdrv_get_info(out_bs, &bdi) < 0)
|
||||
@@ -788,6 +789,7 @@ static int img_convert(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
}
|
||||
qemu_free(buf);
|
||||
bdrv_delete(out_bs);
|
||||
for (bs_i = 0; bs_i < bs_n; bs_i++)
|
||||
bdrv_delete(bs[bs_i]);
|
||||
|
||||
+1
-1
@@ -888,7 +888,7 @@ ETEXI
|
||||
.name = "balloon",
|
||||
.args_type = "value:M",
|
||||
.params = "target",
|
||||
.help = "request VM to change it's memory allocation (in MB)",
|
||||
.help = "request VM to change its memory allocation (in MB)",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = do_balloon,
|
||||
},
|
||||
|
||||
+1
-1
@@ -467,7 +467,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
} while (persistent || nb_fds > 1);
|
||||
qemu_free(data);
|
||||
qemu_vfree(data);
|
||||
|
||||
close(sharing_fds[0]);
|
||||
bdrv_close(bs);
|
||||
|
||||
+30
-9
@@ -404,6 +404,12 @@ ETEXI
|
||||
|
||||
DEF("device", HAS_ARG, QEMU_OPTION_device,
|
||||
"-device driver[,options] add device\n")
|
||||
STEXI
|
||||
@item -device @var{driver}[,@var{option}[,...]]
|
||||
Add device @var{driver}. Depending on the device type,
|
||||
@var{option} (typically @var{key}=@var{value}) may be useful.
|
||||
ETEXI
|
||||
|
||||
DEF("name", HAS_ARG, QEMU_OPTION_name,
|
||||
"-name string1[,process=string2] set the name of the guest\n"
|
||||
" string1 sets the window title and string2 the process name (on Linux)\n")
|
||||
@@ -962,7 +968,7 @@ the guest, use the following:
|
||||
|
||||
@example
|
||||
# on the host
|
||||
qemu -net user,hostfwd=tcp:5555::23 [...]
|
||||
qemu -net user,hostfwd=tcp::5555-:23 [...]
|
||||
telnet localhost 5555
|
||||
@end example
|
||||
|
||||
@@ -1108,7 +1114,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
|
||||
"-chardev serial,id=id,path=path\n"
|
||||
#else
|
||||
"-chardev pty,id=id\n"
|
||||
"-chardev stdio,id=id\n"
|
||||
"-chardev stdio,id=id,[,signal=on|off]\n"
|
||||
#endif
|
||||
#ifdef CONFIG_BRLAPI
|
||||
"-chardev braille,id=id\n"
|
||||
@@ -1284,10 +1290,14 @@ not take any options.
|
||||
|
||||
@option{pty} is not available on Windows hosts.
|
||||
|
||||
@item -chardev stdio ,id=@var{id}
|
||||
@item -chardev stdio ,id=@var{id} [,signal=on|off]
|
||||
Connect to standard input and standard output of the qemu process.
|
||||
@option{stdio} does not take any options. @option{stdio} is not available on
|
||||
Windows hosts.
|
||||
|
||||
@option{signal} controls if signals are enabled on the terminal, that includes
|
||||
exiting QEMU with the key sequence @key{Control-c}. This option is enabled by
|
||||
default, use @option{signal=off} to disable it.
|
||||
|
||||
@option{stdio} is not available on Windows hosts.
|
||||
|
||||
@item -chardev braille ,id=@var{id}
|
||||
|
||||
@@ -1893,6 +1903,8 @@ ETEXI
|
||||
DEF("nodefaults", 0, QEMU_OPTION_nodefaults, \
|
||||
"-nodefaults don't create default devices.\n")
|
||||
STEXI
|
||||
@item -nodefaults
|
||||
Don't create default devices.
|
||||
ETEXI
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -1915,10 +1927,6 @@ Immediately before starting guest execution, drop root privileges, switching
|
||||
to the specified user.
|
||||
ETEXI
|
||||
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
|
||||
DEF("prom-env", HAS_ARG, QEMU_OPTION_prom_env,
|
||||
"-prom-env variable=value\n"
|
||||
@@ -1934,6 +1942,19 @@ DEF("old-param", 0, QEMU_OPTION_old_param,
|
||||
#endif
|
||||
DEF("readconfig", HAS_ARG, QEMU_OPTION_readconfig,
|
||||
"-readconfig <file>\n")
|
||||
STEXI
|
||||
@item -readconfig @var{file}
|
||||
Read device configuration from @var{file}.
|
||||
ETEXI
|
||||
DEF("writeconfig", HAS_ARG, QEMU_OPTION_writeconfig,
|
||||
"-writeconfig <file>\n"
|
||||
" read/write config file\n")
|
||||
STEXI
|
||||
@item -writeconfig @var{file}
|
||||
Write device configuration to @var{file}.
|
||||
ETEXI
|
||||
|
||||
HXCOMM This is the last statement. Insert new options before this line!
|
||||
STEXI
|
||||
@end table
|
||||
ETEXI
|
||||
+6
-5
@@ -130,7 +130,8 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
|
||||
ai.ai_family = PF_UNSPEC;
|
||||
ai.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (qemu_opt_get(opts, "port") == NULL) {
|
||||
if ((qemu_opt_get(opts, "host") == NULL) ||
|
||||
(qemu_opt_get(opts, "port") == NULL)) {
|
||||
fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
@@ -424,7 +425,7 @@ static int inet_parse(QemuOpts *opts, const char *str)
|
||||
__FUNCTION__, str);
|
||||
return -1;
|
||||
}
|
||||
qemu_opt_set(opts, "ipv6", "yes");
|
||||
qemu_opt_set(opts, "ipv6", "on");
|
||||
} else if (qemu_isdigit(str[0])) {
|
||||
/* IPv4 addr */
|
||||
if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
|
||||
@@ -432,7 +433,7 @@ static int inet_parse(QemuOpts *opts, const char *str)
|
||||
__FUNCTION__, str);
|
||||
return -1;
|
||||
}
|
||||
qemu_opt_set(opts, "ipv4", "yes");
|
||||
qemu_opt_set(opts, "ipv4", "on");
|
||||
} else {
|
||||
/* hostname */
|
||||
if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
|
||||
@@ -450,9 +451,9 @@ static int inet_parse(QemuOpts *opts, const char *str)
|
||||
if (h)
|
||||
qemu_opt_set(opts, "to", h+4);
|
||||
if (strstr(optstr, ",ipv4"))
|
||||
qemu_opt_set(opts, "ipv4", "yes");
|
||||
qemu_opt_set(opts, "ipv4", "on");
|
||||
if (strstr(optstr, ",ipv6"))
|
||||
qemu_opt_set(opts, "ipv6", "yes");
|
||||
qemu_opt_set(opts, "ipv6", "on");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule roms/seabios updated: 5da68339ec...9fb3f4d950.
@@ -1696,7 +1696,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
|
||||
sn->vm_clock_nsec = qemu_get_clock(vm_clock);
|
||||
|
||||
/* Delete old snapshots of the same name */
|
||||
if (del_existing_snapshots(mon, name) < 0) {
|
||||
if (name && del_existing_snapshots(mon, name) < 0) {
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
|
||||
@@ -525,6 +525,7 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
|
||||
static void toggle_full_screen(DisplayState *ds)
|
||||
{
|
||||
gui_fullscreen = !gui_fullscreen;
|
||||
do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
|
||||
if (gui_fullscreen) {
|
||||
scaling_active = 0;
|
||||
gui_saved_grab = gui_grab;
|
||||
|
||||
+1
-1
@@ -179,7 +179,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
|
||||
close(s);
|
||||
|
||||
i = 0;
|
||||
bptr = strdup(ex); /* No need to free() this */
|
||||
bptr = qemu_strdup(ex); /* No need to free() this */
|
||||
if (do_pty == 1) {
|
||||
/* Setup "slirp.telnetd -x" */
|
||||
argv[i++] = "slirp.telnetd";
|
||||
|
||||
+2
-2
@@ -2043,7 +2043,7 @@ static inline uint16_t add16_usat(uint16_t a, uint16_t b)
|
||||
|
||||
static inline uint16_t sub16_usat(uint16_t a, uint16_t b)
|
||||
{
|
||||
if (a < b)
|
||||
if (a > b)
|
||||
return a - b;
|
||||
else
|
||||
return 0;
|
||||
@@ -2060,7 +2060,7 @@ static inline uint8_t add8_usat(uint8_t a, uint8_t b)
|
||||
|
||||
static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
|
||||
{
|
||||
if (a < b)
|
||||
if (a > b)
|
||||
return a - b;
|
||||
else
|
||||
return 0;
|
||||
|
||||
@@ -73,8 +73,8 @@ uint32_t HELPER(glue(PFX,subaddx))(uint32_t a, uint32_t b GE_ARG)
|
||||
uint32_t res = 0;
|
||||
DECLARE_GE;
|
||||
|
||||
ADD16(a, b, 0);
|
||||
SUB16(a >> 16, b >> 16, 1);
|
||||
ADD16(a, b >> 16, 0);
|
||||
SUB16(a >> 16, b, 1);
|
||||
SET_GE;
|
||||
return res;
|
||||
}
|
||||
@@ -84,8 +84,8 @@ uint32_t HELPER(glue(PFX,addsubx))(uint32_t a, uint32_t b GE_ARG)
|
||||
uint32_t res = 0;
|
||||
DECLARE_GE;
|
||||
|
||||
SUB16(a, b, 0);
|
||||
ADD16(a >> 16, b >> 16, 1);
|
||||
SUB16(a, b >> 16, 0);
|
||||
ADD16(a >> 16, b, 1);
|
||||
SET_GE;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -561,7 +561,7 @@ static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
|
||||
|
||||
/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */
|
||||
#define PAS_OP(pfx) \
|
||||
switch (op2) { \
|
||||
switch (op1) { \
|
||||
case 0: gen_pas_helper(glue(pfx,add8)); break; \
|
||||
case 1: gen_pas_helper(glue(pfx,add16)); break; \
|
||||
case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
|
||||
@@ -573,7 +573,7 @@ static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
|
||||
{
|
||||
TCGv_ptr tmp;
|
||||
|
||||
switch (op1) {
|
||||
switch (op2) {
|
||||
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
|
||||
case 0:
|
||||
tmp = tcg_temp_new_ptr();
|
||||
|
||||
+16
-8
@@ -2047,8 +2047,8 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
|
||||
gen_op_movl_A0_im(disp);
|
||||
}
|
||||
}
|
||||
/* XXX: index == 4 is always invalid */
|
||||
if (havesib && (index != 4 || scale != 0)) {
|
||||
/* index == 4 means no index */
|
||||
if (havesib && (index != 4)) {
|
||||
#ifdef TARGET_X86_64
|
||||
if (s->aflag == 2) {
|
||||
gen_op_addq_A0_reg_sN(scale, index);
|
||||
@@ -3165,12 +3165,17 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
|
||||
case 0x1e7: /* movntdq */
|
||||
case 0x02b: /* movntps */
|
||||
case 0x12b: /* movntps */
|
||||
case 0x3f0: /* lddqu */
|
||||
if (mod == 3)
|
||||
goto illegal_op;
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
|
||||
break;
|
||||
case 0x3f0: /* lddqu */
|
||||
if (mod == 3)
|
||||
goto illegal_op;
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
|
||||
break;
|
||||
case 0x22b: /* movntss */
|
||||
case 0x32b: /* movntsd */
|
||||
if (mod == 3)
|
||||
@@ -4591,9 +4596,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
/* operand size for jumps is 64 bit */
|
||||
ot = OT_QUAD;
|
||||
} else if (op == 3 || op == 5) {
|
||||
/* for call calls, the operand is 16 or 32 bit, even
|
||||
in long mode */
|
||||
ot = dflag ? OT_LONG : OT_WORD;
|
||||
ot = dflag ? OT_LONG + (rex_w == 1) : OT_WORD;
|
||||
} else if (op == 6) {
|
||||
/* default push size is 64 bit */
|
||||
ot = dflag ? OT_QUAD : OT_WORD;
|
||||
@@ -5293,6 +5296,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
break;
|
||||
|
||||
case 0x91 ... 0x97: /* xchg R, EAX */
|
||||
do_xchg_reg_eax:
|
||||
ot = dflag + OT_WORD;
|
||||
reg = (b & 7) | REX_B(s);
|
||||
rm = R_EAX;
|
||||
@@ -6663,10 +6667,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
|
||||
/************************/
|
||||
/* misc */
|
||||
case 0x90: /* nop */
|
||||
/* XXX: xchg + rex handling */
|
||||
/* XXX: correct lock test for all insn */
|
||||
if (prefixes & PREFIX_LOCK)
|
||||
if (prefixes & PREFIX_LOCK) {
|
||||
goto illegal_op;
|
||||
}
|
||||
/* If REX_B is set, then this is xchg eax, r8d, not a nop. */
|
||||
if (REX_B(s)) {
|
||||
goto do_xchg_reg_eax;
|
||||
}
|
||||
if (prefixes & PREFIX_REPZ) {
|
||||
gen_svm_check_intercept(s, pc_start, SVM_EXIT_PAUSE);
|
||||
}
|
||||
|
||||
+2
-2
@@ -590,8 +590,8 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
#define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault
|
||||
void do_interrupt (CPUState *env);
|
||||
void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
|
||||
target_phys_addr_t do_translate_address (CPUState *env, target_ulong address,
|
||||
int rw);
|
||||
target_phys_addr_t cpu_mips_translate_address (CPUState *env, target_ulong address,
|
||||
int rw);
|
||||
|
||||
static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
|
||||
{
|
||||
|
||||
@@ -311,7 +311,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
target_phys_addr_t do_translate_address(CPUState *env, target_ulong address, int rw)
|
||||
target_phys_addr_t cpu_mips_translate_address(CPUState *env, target_ulong address, int rw)
|
||||
{
|
||||
target_phys_addr_t physical;
|
||||
int prot;
|
||||
@@ -326,10 +326,10 @@ target_phys_addr_t do_translate_address(CPUState *env, target_ulong address, int
|
||||
address, rw, access_type);
|
||||
if (ret != TLBRET_MATCH) {
|
||||
raise_mmu_exception(env, address, rw, ret);
|
||||
cpu_loop_exit();
|
||||
return -1LL;
|
||||
} else {
|
||||
return physical;
|
||||
}
|
||||
|
||||
return physical;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+16
-2
@@ -276,10 +276,24 @@ void helper_dmultu (target_ulong arg1, target_ulong arg2)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
static inline target_phys_addr_t do_translate_address(target_ulong address, int rw)
|
||||
{
|
||||
target_phys_addr_t lladdr;
|
||||
|
||||
lladdr = cpu_mips_translate_address(env, address, rw);
|
||||
|
||||
if (lladdr == -1LL) {
|
||||
cpu_loop_exit();
|
||||
} else {
|
||||
return lladdr;
|
||||
}
|
||||
}
|
||||
|
||||
#define HELPER_LD_ATOMIC(name, insn) \
|
||||
target_ulong helper_##name(target_ulong arg, int mem_idx) \
|
||||
{ \
|
||||
env->lladdr = do_translate_address(env, arg, 0); \
|
||||
env->lladdr = do_translate_address(arg, 0); \
|
||||
env->llval = do_##insn(arg, mem_idx); \
|
||||
return env->llval; \
|
||||
}
|
||||
@@ -298,7 +312,7 @@ target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
|
||||
env->CP0_BadVAddr = arg2; \
|
||||
helper_raise_exception(EXCP_AdES); \
|
||||
} \
|
||||
if (do_translate_address(env, arg2, 1) == env->lladdr) { \
|
||||
if (do_translate_address(arg2, 1) == env->lladdr) { \
|
||||
tmp = do_##ld_insn(arg2, mem_idx); \
|
||||
if (tmp == env->llval) { \
|
||||
do_##st_insn(arg2, arg1, mem_idx); \
|
||||
|
||||
@@ -821,7 +821,7 @@ static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv
|
||||
static inline void check_cp0_enabled(DisasContext *ctx)
|
||||
{
|
||||
if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0)))
|
||||
generate_exception_err(ctx, EXCP_CpU, 1);
|
||||
generate_exception_err(ctx, EXCP_CpU, 0);
|
||||
}
|
||||
|
||||
static inline void check_cp1_enabled(DisasContext *ctx)
|
||||
@@ -1451,6 +1451,8 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
|
||||
tcg_gen_rotri_i32(t1, t1, uimm);
|
||||
tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
|
||||
tcg_temp_free_i32(t1);
|
||||
} else {
|
||||
tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
|
||||
}
|
||||
opn = "rotr";
|
||||
} else {
|
||||
@@ -1489,6 +1491,8 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
|
||||
if (env->insn_flags & ISA_MIPS32R2) {
|
||||
if (uimm != 0) {
|
||||
tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm);
|
||||
} else {
|
||||
tcg_gen_mov_tl(cpu_gpr[rt], t0);
|
||||
}
|
||||
opn = "drotr";
|
||||
} else {
|
||||
@@ -2757,7 +2761,7 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
|
||||
case OPC_DINSU:
|
||||
if (lsb > msb)
|
||||
goto fail;
|
||||
mask = ((1ULL << (msb - lsb + 1)) - 1) << lsb;
|
||||
mask = ((1ULL << (msb - lsb + 1)) - 1) << (lsb + 32);
|
||||
gen_load_gpr(t0, rt);
|
||||
tcg_gen_andi_tl(t0, t0, ~mask);
|
||||
tcg_gen_shli_tl(t1, t1, lsb + 32);
|
||||
|
||||
@@ -2066,7 +2066,6 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
|
||||
srr1 = SPR_SRR1;
|
||||
asrr0 = -1;
|
||||
asrr1 = -1;
|
||||
msr &= ~((target_ulong)0x783F0000);
|
||||
switch (excp) {
|
||||
case POWERPC_EXCP_NONE:
|
||||
/* Should never happen */
|
||||
|
||||
@@ -1646,20 +1646,20 @@ static inline void do_rfi(target_ulong nip, target_ulong msr,
|
||||
void helper_rfi (void)
|
||||
{
|
||||
do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
|
||||
~((target_ulong)0x0), 1);
|
||||
~((target_ulong)0x783F0000), 1);
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
void helper_rfid (void)
|
||||
{
|
||||
do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
|
||||
~((target_ulong)0x0), 0);
|
||||
~((target_ulong)0x783F0000), 0);
|
||||
}
|
||||
|
||||
void helper_hrfid (void)
|
||||
{
|
||||
do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
|
||||
~((target_ulong)0x0), 0);
|
||||
~((target_ulong)0x783F0000), 0);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -167,6 +167,7 @@ int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw,
|
||||
void do_interrupt(CPUSH4State * env);
|
||||
|
||||
void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
|
||||
void cpu_sh4_invalidate_tlb(CPUSH4State *s);
|
||||
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
|
||||
uint32_t mem_value);
|
||||
|
||||
@@ -222,6 +223,7 @@ enum {
|
||||
/* MMU control register */
|
||||
#define MMUCR 0x1F000010
|
||||
#define MMUCR_AT (1<<0)
|
||||
#define MMUCR_TI (1<<2)
|
||||
#define MMUCR_SV (1<<8)
|
||||
#define MMUCR_URC_BITS (6)
|
||||
#define MMUCR_URC_OFFSET (10)
|
||||
|
||||
+20
-2
@@ -377,7 +377,7 @@ static int get_mmu_address(CPUState * env, target_ulong * physical,
|
||||
n = find_itlb_entry(env, address, use_asid, 1);
|
||||
if (n >= 0) {
|
||||
matching = &env->itlb[n];
|
||||
if ((env->sr & SR_MD) & !(matching->pr & 2))
|
||||
if (!(env->sr & SR_MD) && !(matching->pr & 2))
|
||||
n = MMU_ITLB_VIOLATION;
|
||||
else
|
||||
*prot = PAGE_READ;
|
||||
@@ -430,7 +430,7 @@ static int get_physical_address(CPUState * env, target_ulong * physical,
|
||||
if ((address >= 0x80000000 && address < 0xc0000000) ||
|
||||
address >= 0xe0000000) {
|
||||
if (!(env->sr & SR_MD)
|
||||
&& (address < 0xe0000000 || address > 0xe4000000)) {
|
||||
&& (address < 0xe0000000 || address >= 0xe4000000)) {
|
||||
/* Unauthorized access in user mode (only store queues are available) */
|
||||
fprintf(stderr, "Unauthorized access\n");
|
||||
if (rw == 0)
|
||||
@@ -574,6 +574,24 @@ void cpu_load_tlb(CPUSH4State * env)
|
||||
entry->tc = (uint8_t)cpu_ptea_tc(env->ptea);
|
||||
}
|
||||
|
||||
void cpu_sh4_invalidate_tlb(CPUSH4State *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* UTLB */
|
||||
for (i = 0; i < UTLB_SIZE; i++) {
|
||||
tlb_t * entry = &s->utlb[i];
|
||||
entry->v = 0;
|
||||
}
|
||||
/* ITLB */
|
||||
for (i = 0; i < UTLB_SIZE; i++) {
|
||||
tlb_t * entry = &s->utlb[i];
|
||||
entry->v = 0;
|
||||
}
|
||||
|
||||
tlb_flush(s, 1);
|
||||
}
|
||||
|
||||
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
|
||||
uint32_t mem_value)
|
||||
{
|
||||
|
||||
@@ -1905,7 +1905,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
ctx.bstate = BS_NONE;
|
||||
ctx.sr = env->sr;
|
||||
ctx.fpscr = env->fpscr;
|
||||
ctx.memidx = (env->sr & SR_MD) ? 1 : 0;
|
||||
ctx.memidx = (env->sr & SR_MD) == 0 ? 1 : 0;
|
||||
/* We don't know if the delayed pc came from a dynamic or static branch,
|
||||
so assume it is a dynamic branch. */
|
||||
ctx.delayed_pc = -1; /* use delayed pc from env pointer */
|
||||
|
||||
@@ -1697,12 +1697,15 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
|
||||
|
||||
void tcg_target_qemu_prologue(TCGContext *s)
|
||||
{
|
||||
/* stmdb sp!, { r9 - r11, lr } */
|
||||
tcg_out32(s, (COND_AL << 28) | 0x092d4e00);
|
||||
/* Theoretically there is no need to save r12, but an
|
||||
even number of registers to be saved as per EABI */
|
||||
|
||||
/* stmdb sp!, { r4 - r12, lr } */
|
||||
tcg_out32(s, (COND_AL << 28) | 0x092d5ff0);
|
||||
|
||||
tcg_out_bx(s, COND_AL, TCG_REG_R0);
|
||||
tb_ret_addr = s->code_ptr;
|
||||
|
||||
/* ldmia sp!, { r9 - r11, pc } */
|
||||
tcg_out32(s, (COND_AL << 28) | 0x08bd8e00);
|
||||
/* ldmia sp!, { r4 - r12, pc } */
|
||||
tcg_out32(s, (COND_AL << 28) | 0x08bd9ff0);
|
||||
}
|
||||
+35
-23
@@ -339,6 +339,17 @@ static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int i
|
||||
tcg_out32(s, inst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Type branch
|
||||
*/
|
||||
static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs)
|
||||
{
|
||||
/* We need to keep the offset unchanged for retranslation */
|
||||
uint16_t offset = (uint16_t)(*(uint32_t *) &s->code_ptr);
|
||||
|
||||
tcg_out_opc_imm(s, opc, rt, rs, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Type sa
|
||||
*/
|
||||
@@ -469,42 +480,42 @@ static void tcg_out_brcond(TCGContext *s, int cond, int arg1,
|
||||
|
||||
switch (cond) {
|
||||
case TCG_COND_EQ:
|
||||
tcg_out_opc_imm(s, OPC_BEQ, arg1, arg2, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, arg1, arg2);
|
||||
break;
|
||||
case TCG_COND_NE:
|
||||
tcg_out_opc_imm(s, OPC_BNE, arg1, arg2, 0);
|
||||
tcg_out_opc_br(s, OPC_BNE, arg1, arg2);
|
||||
break;
|
||||
case TCG_COND_LT:
|
||||
tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
|
||||
tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
|
||||
break;
|
||||
case TCG_COND_LTU:
|
||||
tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
|
||||
tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
|
||||
break;
|
||||
case TCG_COND_GE:
|
||||
tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
|
||||
tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
|
||||
break;
|
||||
case TCG_COND_GEU:
|
||||
tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
|
||||
tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
|
||||
break;
|
||||
case TCG_COND_LE:
|
||||
tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
|
||||
tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
|
||||
break;
|
||||
case TCG_COND_LEU:
|
||||
tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
|
||||
tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
|
||||
break;
|
||||
case TCG_COND_GT:
|
||||
tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
|
||||
tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
|
||||
break;
|
||||
case TCG_COND_GTU:
|
||||
tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
|
||||
tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
|
||||
break;
|
||||
default:
|
||||
tcg_abort();
|
||||
@@ -553,7 +564,7 @@ static void tcg_out_brcond2(TCGContext *s, int cond, int arg1,
|
||||
}
|
||||
|
||||
label_ptr = s->code_ptr;
|
||||
tcg_out_opc_imm(s, OPC_BNE, arg2, arg4, 0);
|
||||
tcg_out_opc_br(s, OPC_BNE, arg2, arg4);
|
||||
tcg_out_nop(s);
|
||||
|
||||
switch(cond) {
|
||||
@@ -670,20 +681,20 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||
|
||||
# if TARGET_LONG_BITS == 64
|
||||
label3_ptr = s->code_ptr;
|
||||
tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0);
|
||||
tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT);
|
||||
tcg_out_nop(s);
|
||||
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
|
||||
offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_memh);
|
||||
|
||||
label1_ptr = s->code_ptr;
|
||||
tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT);
|
||||
tcg_out_nop(s);
|
||||
|
||||
reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr);
|
||||
# else
|
||||
label1_ptr = s->code_ptr;
|
||||
tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT);
|
||||
tcg_out_nop(s);
|
||||
# endif
|
||||
|
||||
@@ -725,15 +736,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||
}
|
||||
|
||||
label2_ptr = s->code_ptr;
|
||||
tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
|
||||
tcg_out_nop(s);
|
||||
|
||||
/* label1: fast path */
|
||||
reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr);
|
||||
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_REG_V0, TCG_REG_A0,
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0,
|
||||
offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml);
|
||||
tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl);
|
||||
tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_A0, addr_regl);
|
||||
|
||||
addr_reg1 = TCG_REG_V0;
|
||||
#endif
|
||||
@@ -857,20 +868,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||
|
||||
# if TARGET_LONG_BITS == 64
|
||||
label3_ptr = s->code_ptr;
|
||||
tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0);
|
||||
tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT);
|
||||
tcg_out_nop(s);
|
||||
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
|
||||
offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_memh);
|
||||
|
||||
label1_ptr = s->code_ptr;
|
||||
tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT);
|
||||
tcg_out_nop(s);
|
||||
|
||||
reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr);
|
||||
# else
|
||||
label1_ptr = s->code_ptr;
|
||||
tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT);
|
||||
tcg_out_nop(s);
|
||||
# endif
|
||||
|
||||
@@ -911,7 +922,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||
tcg_out_nop(s);
|
||||
|
||||
label2_ptr = s->code_ptr;
|
||||
tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0);
|
||||
tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
|
||||
tcg_out_nop(s);
|
||||
|
||||
/* label1: fast path */
|
||||
@@ -1262,7 +1273,9 @@ static const TCGTargetOpDef mips_op_defs[] = {
|
||||
};
|
||||
|
||||
static int tcg_target_callee_save_regs[] = {
|
||||
#if 0 /* used for the global env (TCG_AREG0), so no need to save */
|
||||
TCG_REG_S0,
|
||||
#endif
|
||||
TCG_REG_S1,
|
||||
TCG_REG_S2,
|
||||
TCG_REG_S3,
|
||||
@@ -1271,8 +1284,7 @@ static int tcg_target_callee_save_regs[] = {
|
||||
TCG_REG_S6,
|
||||
TCG_REG_S7,
|
||||
TCG_REG_GP,
|
||||
/* TCG_REG_FP, */ /* currently used for the global env, so np
|
||||
need to save */
|
||||
TCG_REG_FP,
|
||||
TCG_REG_RA, /* should be last for ABI compliance */
|
||||
};
|
||||
|
||||
|
||||
@@ -92,9 +92,9 @@ enum {
|
||||
#undef TCG_TARGET_HAS_ext16u_i32 /* andi rt, rs, 0xffff */
|
||||
|
||||
/* Note: must be synced with dyngen-exec.h */
|
||||
#define TCG_AREG0 TCG_REG_FP
|
||||
#define TCG_AREG1 TCG_REG_S0
|
||||
#define TCG_AREG2 TCG_REG_S1
|
||||
#define TCG_AREG0 TCG_REG_S0
|
||||
#define TCG_AREG1 TCG_REG_S1
|
||||
#define TCG_AREG2 TCG_REG_FP
|
||||
|
||||
#include <sys/cachectl.h>
|
||||
|
||||
|
||||
+1
-1
@@ -1036,7 +1036,7 @@ USBDevice *usb_host_device_open(const char *devname)
|
||||
qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
|
||||
qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
|
||||
qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
|
||||
qdev_init(&dev->qdev);
|
||||
qdev_init_nofail(&dev->qdev);
|
||||
return dev;
|
||||
|
||||
fail:
|
||||
|
||||
@@ -2573,9 +2573,9 @@ static void numa_add(const char *optarg)
|
||||
fprintf(stderr,
|
||||
"only 63 CPUs in NUMA mode supported.\n");
|
||||
}
|
||||
value = (1 << (endvalue + 1)) - (1 << value);
|
||||
value = (2ULL << endvalue) - (1ULL << value);
|
||||
} else {
|
||||
value = 1 << value;
|
||||
value = 1ULL << value;
|
||||
}
|
||||
}
|
||||
node_cpumask[nodenr] = value;
|
||||
@@ -3471,6 +3471,8 @@ static int cpu_can_run(CPUState *env)
|
||||
return 0;
|
||||
if (env->stopped)
|
||||
return 0;
|
||||
if (!vm_running)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -4042,14 +4044,15 @@ static void tcg_cpu_exec(void)
|
||||
for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) {
|
||||
CPUState *env = cur_cpu = next_cpu;
|
||||
|
||||
if (!vm_running)
|
||||
break;
|
||||
if (timer_alarm_pending) {
|
||||
timer_alarm_pending = 0;
|
||||
break;
|
||||
}
|
||||
if (cpu_can_run(env))
|
||||
ret = qemu_cpu_exec(env);
|
||||
else if (env->stop)
|
||||
break;
|
||||
|
||||
if (ret == EXCP_DEBUG) {
|
||||
gdb_set_stop_cpu(env);
|
||||
debug_requested = 1;
|
||||
@@ -4850,7 +4853,7 @@ int main(int argc, char **argv, char **envp)
|
||||
const char *gdbstub_dev = NULL;
|
||||
uint32_t boot_devices_bitmap = 0;
|
||||
int i;
|
||||
int snapshot, linux_boot, net_boot;
|
||||
int snapshot, linux_boot;
|
||||
const char *initrd_filename;
|
||||
const char *kernel_filename, *kernel_cmdline;
|
||||
char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */
|
||||
@@ -5367,6 +5370,9 @@ int main(int argc, char **argv, char **envp)
|
||||
case QEMU_OPTION_serial:
|
||||
add_device_config(DEV_SERIAL, optarg);
|
||||
default_serial = 0;
|
||||
if (strncmp(optarg, "mon:", 4) == 0) {
|
||||
default_monitor = 0;
|
||||
}
|
||||
break;
|
||||
case QEMU_OPTION_watchdog:
|
||||
if (watchdog) {
|
||||
@@ -5385,10 +5391,16 @@ int main(int argc, char **argv, char **envp)
|
||||
case QEMU_OPTION_virtiocon:
|
||||
add_device_config(DEV_VIRTCON, optarg);
|
||||
default_virtcon = 0;
|
||||
if (strncmp(optarg, "mon:", 4) == 0) {
|
||||
default_monitor = 0;
|
||||
}
|
||||
break;
|
||||
case QEMU_OPTION_parallel:
|
||||
add_device_config(DEV_PARALLEL, optarg);
|
||||
default_parallel = 0;
|
||||
if (strncmp(optarg, "mon:", 4) == 0) {
|
||||
default_monitor = 0;
|
||||
}
|
||||
break;
|
||||
case QEMU_OPTION_loadvm:
|
||||
loadvm = optarg;
|
||||
@@ -5791,6 +5803,12 @@ int main(int argc, char **argv, char **envp)
|
||||
fprintf(stderr, "failed to initialize KVM\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
/* without kvm enabled, we can only support 4095 MB RAM */
|
||||
if (ram_size > (4095UL << 20)) {
|
||||
fprintf(stderr, "qemu: without kvm support at most 4095 MB RAM can be simulated\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (qemu_init_main_loop()) {
|
||||
@@ -5834,9 +5852,6 @@ int main(int argc, char **argv, char **envp)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
|
||||
net_set_boot_mask(net_boot);
|
||||
|
||||
/* init the bluetooth world */
|
||||
if (foreach_device_config(DEV_BT, bt_parse))
|
||||
exit(1);
|
||||
@@ -5968,6 +5983,8 @@ int main(int argc, char **argv, char **envp)
|
||||
if (qemu_opts_foreach(&qemu_device_opts, device_init_func, NULL, 1) != 0)
|
||||
exit(1);
|
||||
|
||||
net_check_clients();
|
||||
|
||||
if (!display_state)
|
||||
dumb_display_init();
|
||||
/* just use the first displaystate for the moment */
|
||||
|
||||
@@ -1421,8 +1421,10 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
|
||||
dz = 1;
|
||||
|
||||
if (vs->absolute) {
|
||||
kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1),
|
||||
y * 0x7FFF / (ds_get_height(vs->ds) - 1),
|
||||
kbd_mouse_event(ds_get_width(vs->ds) > 1 ?
|
||||
x * 0x7FFF / (ds_get_width(vs->ds) - 1) : 0x4000,
|
||||
ds_get_height(vs->ds) > 1 ?
|
||||
y * 0x7FFF / (ds_get_height(vs->ds) - 1) : 0x4000,
|
||||
dz, buttons);
|
||||
} else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
|
||||
x -= 0x7FFF;
|
||||
@@ -2293,7 +2295,7 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
|
||||
static void vnc_refresh(void *opaque)
|
||||
{
|
||||
VncDisplay *vd = opaque;
|
||||
VncState *vs = NULL;
|
||||
VncState *vs = NULL, *vn = NULL;
|
||||
int has_dirty = 0, rects = 0;
|
||||
|
||||
vga_hw_update();
|
||||
@@ -2302,8 +2304,10 @@ static void vnc_refresh(void *opaque)
|
||||
|
||||
vs = vd->clients;
|
||||
while (vs != NULL) {
|
||||
vn = vs->next;
|
||||
rects += vnc_update_client(vs, has_dirty);
|
||||
vs = vs->next;
|
||||
/* vs might be free()ed here */
|
||||
vs = vn;
|
||||
}
|
||||
/* vd->timer could be NULL now if the last client disconnected,
|
||||
* in this case don't update the timer */
|
||||
|
||||
@@ -35,8 +35,20 @@ SECTIONS
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
|
||||
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.rel.plt :
|
||||
{
|
||||
*(.rel.plt)
|
||||
PROVIDE_HIDDEN (__rel_iplt_start = .);
|
||||
*(.rel.iplt)
|
||||
PROVIDE_HIDDEN (__rel_iplt_end = .);
|
||||
}
|
||||
.rela.plt :
|
||||
{
|
||||
*(.rela.plt)
|
||||
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||
*(.rela.iplt)
|
||||
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||
}
|
||||
.init :
|
||||
{
|
||||
KEEP (*(.init))
|
||||
|
||||
Reference in new issue
Block a user