From 18db2af1ebaf0d0bd6c51baec057bff434824593 Mon Sep 17 00:00:00 2001 From: Stephen McKinney Date: Mon, 16 Nov 2020 23:38:46 -0600 Subject: [PATCH 01/67] Add MiniVHD to 86Box. --- .gitignore | 1 + src/disk/minivhd/CREDITS.md | 12 + src/disk/minivhd/LICENSE | 21 + src/disk/minivhd/cwalk.c | 1421 ++++++++++++++++++++++++++ src/disk/minivhd/cwalk.h | 457 +++++++++ src/disk/minivhd/libxml2_encoding.c | 447 ++++++++ src/disk/minivhd/libxml2_encoding.h | 12 + src/disk/minivhd/minivhd.h | 269 +++++ src/disk/minivhd/minivhd_convert.c | 105 ++ src/disk/minivhd/minivhd_create.c | 482 +++++++++ src/disk/minivhd/minivhd_create.h | 8 + src/disk/minivhd/minivhd_internal.h | 96 ++ src/disk/minivhd/minivhd_io.c | 276 +++++ src/disk/minivhd/minivhd_io.h | 132 +++ src/disk/minivhd/minivhd_manage.c | 533 ++++++++++ src/disk/minivhd/minivhd_struct_rw.c | 165 +++ src/disk/minivhd/minivhd_struct_rw.h | 38 + src/disk/minivhd/minivhd_util.c | 323 ++++++ src/disk/minivhd/minivhd_util.h | 136 +++ src/win/Makefile.mingw | 8 +- 20 files changed, 4940 insertions(+), 2 deletions(-) create mode 100644 src/disk/minivhd/CREDITS.md create mode 100644 src/disk/minivhd/LICENSE create mode 100644 src/disk/minivhd/cwalk.c create mode 100644 src/disk/minivhd/cwalk.h create mode 100644 src/disk/minivhd/libxml2_encoding.c create mode 100644 src/disk/minivhd/libxml2_encoding.h create mode 100644 src/disk/minivhd/minivhd.h create mode 100644 src/disk/minivhd/minivhd_convert.c create mode 100644 src/disk/minivhd/minivhd_create.c create mode 100644 src/disk/minivhd/minivhd_create.h create mode 100644 src/disk/minivhd/minivhd_internal.h create mode 100644 src/disk/minivhd/minivhd_io.c create mode 100644 src/disk/minivhd/minivhd_io.h create mode 100644 src/disk/minivhd/minivhd_manage.c create mode 100644 src/disk/minivhd/minivhd_struct_rw.c create mode 100644 src/disk/minivhd/minivhd_struct_rw.h create mode 100644 src/disk/minivhd/minivhd_util.c create mode 100644 src/disk/minivhd/minivhd_util.h diff --git a/.gitignore b/.gitignore index 99e0528fc..5c05ee308 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ src/*.dmp src/NUL src/nvr/ src/roms/ +/.vs diff --git a/src/disk/minivhd/CREDITS.md b/src/disk/minivhd/CREDITS.md new file mode 100644 index 000000000..c494d4e43 --- /dev/null +++ b/src/disk/minivhd/CREDITS.md @@ -0,0 +1,12 @@ +# Credits +MiniVHD Copyright (c) 2019 Sherman Perry + +MiniVHD was made possible with the help of the following projects + +### libxml2 +**Project Home:** http://www.xmlsoft.org/ +**License:** MIT (see src/libxml2_encoding.c for details) + +### cwalk +**Project Home:** https://likle.github.io/cwalk/ +**Licence:** MIT (https://github.com/likle/cwalk/blob/master/LICENSE.md) diff --git a/src/disk/minivhd/LICENSE b/src/disk/minivhd/LICENSE new file mode 100644 index 000000000..2997be44a --- /dev/null +++ b/src/disk/minivhd/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Sherman Perry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/disk/minivhd/cwalk.c b/src/disk/minivhd/cwalk.c new file mode 100644 index 000000000..265de0f72 --- /dev/null +++ b/src/disk/minivhd/cwalk.c @@ -0,0 +1,1421 @@ +#include +#include +#include +#include +#include +#include "cwalk.h" +/** + * We try to default to a different path style depending on the operating + * system. So this should detect whether we should use windows or unix paths. + */ +#if defined(WIN32) || defined(_WIN32) || \ + defined(__WIN32) && !defined(__CYGWIN__) +static enum cwk_path_style path_style = CWK_STYLE_WINDOWS; +#else +static enum cwk_path_style path_style = CWK_STYLE_UNIX; +#endif + +/** + * This is a list of separators used in different styles. Windows can read + * multiple separators, but it generally outputs just a backslash. The output + * will always use the first character for the output. + */ +static const char *separators[] = {[CWK_STYLE_WINDOWS] = "\\/", + [CWK_STYLE_UNIX] = "/"}; + +/** + * A joined path represents multiple path strings which are concatenated, but + * not (necessarily) stored in contiguous memory. The joined path allows to + * iterate over the segments as if it was one piece of path. + */ +struct cwk_segment_joined +{ + struct cwk_segment segment; + const char **paths; + size_t path_index; +}; + +static size_t cwk_path_output_sized(char *buffer, size_t buffer_size, + size_t position, const char *str, size_t length) +{ + size_t amount_written; + + // First we determine the amount which we can write to the buffer. There are + // three cases. In the first case we have enough to store the whole string in + // it. In the second one we can only store a part of it, and in the third we + // have no space left. + if (buffer_size > position + length) { + amount_written = length; + } else if (buffer_size > position) { + amount_written = buffer_size - position; + } else { + amount_written = 0; + } + + // If we actually want to write out something we will do that here. We will + // always append a '\0', this way we are guaranteed to have a valid string at + // all times. + if (amount_written > 0) { + memmove(&buffer[position], str, amount_written); + } + + // Return the theoretical length which would have been written when everything + // would have fit in the buffer. + return length; +} + +static size_t cwk_path_output_current(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a "current" directory, which is a single character. This + // character is currently not style dependant. + return cwk_path_output_sized(buffer, buffer_size, position, ".", 1); +} + +static size_t cwk_path_output_back(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a "back" directory, which ahs two characters. This + // character is currently not style dependant. + return cwk_path_output_sized(buffer, buffer_size, position, "..", 2); +} + +static size_t cwk_path_output_separator(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a separator, which is a single character. + return cwk_path_output_sized(buffer, buffer_size, position, + separators[path_style], 1); +} + +static size_t cwk_path_output_dot(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a dot, which is a single character. This is used for extensions. + return cwk_path_output_sized(buffer, buffer_size, position, ".", 1); +} + +static size_t cwk_path_output(char *buffer, size_t buffer_size, size_t position, + const char *str) +{ + size_t length; + + // This just does a sized output internally, but first measuring the + // null-terminated string. + length = strlen(str); + return cwk_path_output_sized(buffer, buffer_size, position, str, length); +} + +static void cwk_path_terminate_output(char *buffer, size_t buffer_size, + size_t pos) +{ + if (buffer_size > 0) { + if (pos >= buffer_size) { + buffer[buffer_size - 1] = '\0'; + } else { + buffer[pos] = '\0'; + } + } +} + +static bool cwk_path_is_string_equal(const char *first, const char *second, + size_t n) +{ + // If the path style is UNIX, we will compare case sensitively. This can be + // done easily using strncmp. + if (path_style == CWK_STYLE_UNIX) { + return strncmp(first, second, n) == 0; + } + + // However, if this is windows we will have to compare case insensitively. + // Since there is no standard method to do that we will have to do it on our + // own. + while (*first && *second && n > 0) { + // We can consider the string to be not equal if the two lowercase + // characters are not equal. + if (tolower(*first++) != tolower(*second++)) { + return false; + } + + --n; + } + + // We can consider the string to be equal if we either reached n == 0 or both + // cursors point to a null character. + return n == 0 || (*first == '\0' && *second == '\0'); +} + +static const char *cwk_path_find_next_stop(const char *c) +{ + // We just move forward until we find a '\0' or a separator, which will be our + // next "stop". + while (*c != '\0' && !cwk_path_is_separator(c)) { + ++c; + } + + // Return the pointer of the next stop. + return c; +} + +static const char *cwk_path_find_previous_stop(const char *begin, const char *c) +{ + // We just move back until we find a separator or reach the beginning of the + // path, which will be our previous "stop". + while (c > begin && !cwk_path_is_separator(c)) { + --c; + } + + // Return the pointer to the previous stop. We have to return the first + // character after the separator, not on the separator itself. + if (cwk_path_is_separator(c)) { + return c + 1; + } else { + return c; + } +} + +static bool cwk_path_get_first_segment_without_root(const char *path, + const char *segments, struct cwk_segment *segment) +{ + // Let's remember the path. We will move the path pointer afterwards, that's + // why this has to be done first. + segment->path = path; + segment->segments = segments; + + // Now let's check whether this is an empty string. An empty string has no + // segment it could use. + if (*segments == '\0') { + return false; + } + + // If the string starts with separators, we will jump over those. If there is + // only a slash and a '\0' after it, we can't determine the first segment + // since there is none. + while (cwk_path_is_separator(segments)) { + ++segments; + if (*segments == '\0') { + return false; + } + } + + // So this is the beginning of our segment. + segment->begin = segments; + + // Now let's determine the end of the segment, which we do by moving the path + // pointer further until we find a separator. + segments = cwk_path_find_next_stop(segments); + + // And finally, calculate the size of the segment by subtracting the position + // from the end. + segment->size = segments - segment->begin; + segment->end = segments; + + // Tell the caller that we found a segment. + return true; +} + +static bool cwk_path_get_last_segment_without_root(const char *path, + struct cwk_segment *segment) +{ + // Now this is fairly similar to the normal algorithm, however, it will assume + // that there is no root in the path. So we grab the first segment at this + // position, assuming there is no root. + if (!cwk_path_get_first_segment_without_root(path, path, segment)) { + return false; + } + + // Now we find our last segment. The segment struct of the caller + // will contain the last segment, since the function we call here will not + // change the segment struct when it reaches the end. + while (cwk_path_get_next_segment(segment)) { + // We just loop until there is no other segment left. + } + + return true; +} + +static bool cwk_path_get_first_segment_joined(const char **paths, + struct cwk_segment_joined *sj) +{ + bool result; + + // Prepare the first segment. We position the joined segment on the first path + // and assign the path array to the struct. + sj->path_index = 0; + sj->paths = paths; + + // We loop through all paths until we find one which has a segment. The result + // is stored in a variable, so we can let the caller know whether we found one + // or not. + result = false; + while (paths[sj->path_index] != NULL && + (result = cwk_path_get_first_segment(paths[sj->path_index], + &sj->segment)) == false) { + ++sj->path_index; + } + + return result; +} + +static bool cwk_path_get_next_segment_joined(struct cwk_segment_joined *sj) +{ + bool result; + + if (sj->paths[sj->path_index] == NULL) { + // We reached already the end of all paths, so there is no other segment + // left. + return false; + } else if (cwk_path_get_next_segment(&sj->segment)) { + // There was another segment on the current path, so we are good to + // continue. + return true; + } + + // We try to move to the next path which has a segment available. We must at + // least move one further since the current path reached the end. + result = false; + + do { + ++sj->path_index; + + // And we obviously have to stop this loop if there are no more paths left. + if (sj->paths[sj->path_index] == NULL) { + break; + } + + // Grab the first segment of the next path and determine whether this path + // has anything useful in it. There is one more thing we have to consider + // here - for the first time we do this we want to skip the root, but + // afterwards we will consider that to be part of the segments. + result = cwk_path_get_first_segment_without_root(sj->paths[sj->path_index], + sj->paths[sj->path_index], &sj->segment); + + } while (!result); + + // Finally, report the result back to the caller. + return result; +} + +static bool cwk_path_get_previous_segment_joined(struct cwk_segment_joined *sj) +{ + bool result; + + if (*sj->paths == NULL) { + // It's possible that there is no initialized segment available in the + // struct since there are no paths. In that case we can return false, since + // there is no previous segment. + return false; + } else if (cwk_path_get_previous_segment(&sj->segment)) { + // Now we try to get the previous segment from the current path. If we can + // do that successfully, we can let the caller know that we found one. + return true; + } + + result = false; + + do { + // We are done once we reached index 0. In that case there are no more + // segments left. + if (sj->path_index == 0) { + break; + } + + // There is another path which we have to inspect. So we decrease the path + // index. + --sj->path_index; + + // If this is the first path we will have to consider that this path might + // include a root, otherwise we just treat is as a segment. + if (sj->path_index == 0) { + result = cwk_path_get_last_segment(sj->paths[sj->path_index], + &sj->segment); + } else { + result = cwk_path_get_last_segment_without_root(sj->paths[sj->path_index], + &sj->segment); + } + + } while (!result); + + return result; +} + +static bool cwk_path_segment_back_will_be_removed(struct cwk_segment_joined *sj) +{ + enum cwk_segment_type type; + int counter; + + // We are handling back segments here. We must verify how many back segments + // and how many normal segments come before this one to decide whether we keep + // or remove it. + + // The counter determines how many normal segments are our current segment, + // which will popped off before us. If the counter goes above zero it means + // that our segment will be popped as well. + counter = 0; + + // We loop over all previous segments until we either reach the beginning, + // which means our segment will not be dropped or the counter goes above zero. + while (cwk_path_get_previous_segment_joined(sj)) { + + // Now grab the type. The type determines whether we will increase or + // decrease the counter. We don't handle a CWK_CURRENT frame here since it + // has no influence. + type = cwk_path_get_segment_type(&sj->segment); + if (type == CWK_NORMAL) { + // This is a normal segment. The normal segment will increase the counter + // since it neutralizes one back segment. If we go above zero we can + // return immediately. + ++counter; + if (counter > 0) { + return true; + } + } else if (type == CWK_BACK) { + // A CWK_BACK segment will reduce the counter by one. We can not remove a + // back segment as long we are not above zero since we don't have the + // opposite normal segment which we would remove. + --counter; + } + } + + // We never got a count larger than zero, so we will keep this segment alive. + return false; +} + +static bool cwk_path_segment_normal_will_be_removed( + struct cwk_segment_joined *sj) +{ + enum cwk_segment_type type; + int counter; + + // The counter determines how many segments are above our current segment, + // which will popped off before us. If the counter goes below zero it means + // that our segment will be popped as well. + counter = 0; + + // We loop over all following segments until we either reach the end, which + // means our segment will not be dropped or the counter goes below zero. + while (cwk_path_get_next_segment_joined(sj)) { + + // First, grab the type. The type determines whether we will increase or + // decrease the counter. We don't handle a CWK_CURRENT frame here since it + // has no influence. + type = cwk_path_get_segment_type(&sj->segment); + if (type == CWK_NORMAL) { + // This is a normal segment. The normal segment will increase the counter + // since it will be removed by a "../" before us. + ++counter; + } else if (type == CWK_BACK) { + // A CWK_BACK segment will reduce the counter by one. If we are below zero + // we can return immediately. + --counter; + if (counter < 0) { + return true; + } + } + } + + // We never got a negative count, so we will keep this segment alive. + return false; +} + +static bool +cwk_path_segment_will_be_removed(const struct cwk_segment_joined *sj, + bool absolute) +{ + enum cwk_segment_type type; + struct cwk_segment_joined sjc; + + // We copy the joined path so we don't need to modify it. + sjc = *sj; + + // First we check whether this is a CWK_CURRENT or CWK_BACK segment, since + // those will always be dropped. + type = cwk_path_get_segment_type(&sj->segment); + if (type == CWK_CURRENT) { + return true; + } else if (type == CWK_BACK && absolute) { + return true; + } else if (type == CWK_BACK) { + return cwk_path_segment_back_will_be_removed(&sjc); + } else { + return cwk_path_segment_normal_will_be_removed(&sjc); + } +} + +static bool +cwk_path_segment_joined_skip_invisible(struct cwk_segment_joined *sj, + bool absolute) +{ + while (cwk_path_segment_will_be_removed(sj, absolute)) { + if (!cwk_path_get_next_segment_joined(sj)) { + return false; + } + } + + return true; +} + +static void cwk_path_get_root_windows(const char *path, size_t *length) +{ + const char *c; + bool is_device_path; + + // A device path is a path which starts with "\\." or "\\?". A device path can + // be a UNC path as well, in which case it will take up one more segment. + is_device_path = false; + + // We can not determine the root if this is an empty string. So we set the + // root to NULL and the length to zero and cancel the whole thing. + c = path; + *length = 0; + if (!*c) { + return; + } + + // Now we have to verify whether this is a windows network path (UNC), which + // we will consider our root. + if (cwk_path_is_separator(c)) { + ++c; + + // Check whether the path starts with a single back slash, which means this + // is not a network path - just a normal path starting with a backslash. + if (!cwk_path_is_separator(c)) { + // Okay, this is not a network path but we still use the backslash as a + // root. + ++(*length); + return; + } + + // Yes, this is a network or device path. Skip the previous separator. Now + // we need to determine whether this is a device path. We might advance one + // character here if the server name starts with a '?' or a '.', but that's + // fine since we will search for a separator afterwards anyway. + ++c; + is_device_path = (*c == '?' || *c == '.') && cwk_path_is_separator(++c); + if (is_device_path) { + // That's a device path, and the root must be either "\\.\" or "\\?\" + // which is 4 characters long. (at least that's how Windows + // GetFullPathName behaves.) + *length = 4; + return; + } + + // We will grab anything up to the next stop. The next top might be a '\0' + // or another separator. That will be the server name. + c = cwk_path_find_next_stop(c); + + // If this is a separator and not the end of a string we wil have to include + // it. However, if this is a '\0' we must not skip it. + while (cwk_path_is_separator(c)) { + ++c; + } + + // We are now skipping the shared folder name, which will end after the + // next stop. + c = cwk_path_find_next_stop(c); + + // Then there might be a separator at the end. We will include that as well, + // it will mark the path as absolute. + if (cwk_path_is_separator(c)) { + ++c; + } + + // Finally, calculate the size of the root. + *length = c - path; + return; + } + + // Move to the next and check whether this is a colon. + if (*++c == ':') { + *length = 2; + + // Now check whether this is a backslash (or slash). If it is not, we could + // assume that the next character is a '\0' if it is a valid path. However, + // we will not assume that - since ':' is not valid in a path it must be a + // mistake by the caller than. We will try to understand it anyway. + if (cwk_path_is_separator(++c)) { + *length = 3; + } + } +} + +static void cwk_path_get_root_unix(const char *path, size_t *length) +{ + // The slash of the unix path represents the root. There is no root if there + // is no slash. + if (cwk_path_is_separator(path)) { + *length = 1; + } else { + *length = 0; + } +} + +static bool cwk_path_is_root_absolute(const char *path, size_t length) +{ + // This is definitely not absolute if there is no root. + if (length == 0) { + return false; + } + + // If there is a separator at the end of the root, we can safely consider this + // to be an absolute path. + return cwk_path_is_separator(&path[length - 1]); +} + +static size_t cwk_path_join_and_normalize_multiple(const char **paths, + char *buffer, size_t buffer_size) +{ + size_t pos; + bool absolute, has_segment_output; + struct cwk_segment_joined sj; + + // We initialize the position after the root, which should get us started. + cwk_path_get_root(paths[0], &pos); + + // Determine whether the path is absolute or not. We need that to determine + // later on whether we can remove superfluous "../" or not. + absolute = cwk_path_is_root_absolute(paths[0], pos); + + // First copy the root to the output. We will not modify the root. + cwk_path_output_sized(buffer, buffer_size, 0, paths[0], pos); + + // So we just grab the first segment. If there is no segment we will always + // output a "/", since we currently only support absolute paths here. + if (!cwk_path_get_first_segment_joined(paths, &sj)) { + goto done; + } + + // Let's assume that we don't have any segment output for now. We will toggle + // this flag once there is some output. + has_segment_output = false; + + do { + // Check whether we have to drop this segment because of resolving a + // relative path or because it is a CWK_CURRENT segment. + if (cwk_path_segment_will_be_removed(&sj, absolute)) { + continue; + } + + // Remember that we have segment output, so we can handle the trailing slash + // later on. This is necessary since we might have segments but they are all + // removed. + has_segment_output = true; + + // Write out the segment but keep in mind that we need to follow the + // buffer size limitations. That's why we use the path output functions + // here. + pos += cwk_path_output_sized(buffer, buffer_size, pos, sj.segment.begin, + sj.segment.size); + pos += cwk_path_output_separator(buffer, buffer_size, pos); + } while (cwk_path_get_next_segment_joined(&sj)); + + // Remove the trailing slash, but only if we have segment output. We don't + // want to remove anything from the root. + if (has_segment_output) { + --pos; + } else if (pos == 0) { + // This may happen if the path is absolute and all segments have been + // removed. We can not have an empty output - and empty output means we stay + // in the current directory. So we will output a ".". + assert(absolute == false); + pos += cwk_path_output_current(buffer, buffer_size, pos); + } + + // We must append a '\0' in any case, unless the buffer size is zero. If the + // buffer size is zero, which means we can not. +done: + cwk_path_terminate_output(buffer, buffer_size, pos); + + // And finally let our caller know about the total size of the normalized + // path. + return pos; +} + +size_t cwk_path_get_absolute(const char *base, const char *path, char *buffer, + size_t buffer_size) +{ + size_t i; + const char *paths[4]; + + // The basename should be an absolute path if the caller is using the API + // correctly. However, he might not and in that case we will append a fake + // root at the beginning. + if (cwk_path_is_absolute(base)) { + i = 0; + } else { + paths[0] = "/"; + i = 1; + } + + if (cwk_path_is_absolute(path)) { + // If the submitted path is not relative the base path becomes irrelevant. + // We will only normalize the submitted path instead. + paths[i++] = path; + paths[i] = NULL; + } else { + // Otherwise we append the relative path to the base path and normalize it. + // The result will be a new absolute path. + paths[i++] = base; + paths[i++] = path; + paths[i] = NULL; + } + + // Finally join everything together and normalize it. + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +static void cwk_path_skip_segments_until_diverge(struct cwk_segment_joined *bsj, + struct cwk_segment_joined *osj, bool absolute, bool *base_available, + bool *other_available) +{ + // Now looping over all segments until they start to diverge. A path may + // diverge if two segments are not equal or if one path reaches the end. + do { + + // Check whether there is anything available after we skip everything which + // is invisible. We do that for both paths, since we want to let the caller + // know which path has some trailing segments after they diverge. + *base_available = cwk_path_segment_joined_skip_invisible(bsj, absolute); + *other_available = cwk_path_segment_joined_skip_invisible(osj, absolute); + + // We are done if one or both of those paths reached the end. They either + // diverge or both reached the end - but in both cases we can not continue + // here. + if (!*base_available || !*other_available) { + break; + } + + // Compare the content of both segments. We are done if they are not equal, + // since they diverge. + if (!cwk_path_is_string_equal(bsj->segment.begin, osj->segment.begin, + bsj->segment.size)) { + break; + } + + // We keep going until one of those segments reached the end. The next + // segment might be invisible, but we will check for that in the beginning + // of the loop once again. + *base_available = cwk_path_get_next_segment_joined(bsj); + *other_available = cwk_path_get_next_segment_joined(osj); + } while (*base_available && *other_available); +} + +size_t cwk_path_get_relative(const char *base_directory, const char *path, + char *buffer, size_t buffer_size) +{ + size_t pos, base_root_length, path_root_length; + bool absolute, base_available, other_available, has_output; + const char *base_paths[2], *other_paths[2]; + struct cwk_segment_joined bsj, osj; + + pos = 0; + + // First we compare the roots of those two paths. If the roots are not equal + // we can't continue, since there is no way to get a relative path from + // different roots. + cwk_path_get_root(base_directory, &base_root_length); + cwk_path_get_root(path, &path_root_length); + if (!cwk_path_is_string_equal(base_directory, path, base_root_length)) { + return pos; + } + + // Verify whether this is an absolute path. We need to know that since we can + // remove all back-segments if it is. + absolute = cwk_path_is_root_absolute(base_directory, base_root_length); + + // Initialize our joined segments. This will allow us to use the internal + // functions to skip until diverge and invisible. We only have one path in + // them though. + base_paths[0] = base_directory; + base_paths[1] = NULL; + other_paths[0] = path; + other_paths[1] = NULL; + cwk_path_get_first_segment_joined(base_paths, &bsj); + cwk_path_get_first_segment_joined(other_paths, &osj); + + // Okay, now we skip until the segments diverge. We don't have anything to do + // with the segments which are equal. + cwk_path_skip_segments_until_diverge(&bsj, &osj, absolute, &base_available, + &other_available); + + // Assume there is no output until we have got some. We will need this + // information later on to remove trailing slashes or alternatively output a + // current-segment. + has_output = false; + + // So if we still have some segments left in the base path we will now output + // a back segment for all of them. + if (base_available) { + do { + // Skip any invisible segment. We don't care about those and we don't need + // to navigate back because of them. + if (!cwk_path_segment_joined_skip_invisible(&bsj, absolute)) { + break; + } + + // Toggle the flag if we have output. We need to remember that, since we + // want to remove the trailing slash. + has_output = true; + + // Output the back segment and a separator. No need to worry about the + // superfluous segment since it will be removed later on. + pos += cwk_path_output_back(buffer, buffer_size, pos); + pos += cwk_path_output_separator(buffer, buffer_size, pos); + } while (cwk_path_get_next_segment_joined(&bsj)); + } + + // And if we have some segments available of the target path we will output + // all of those. + if (other_available) { + do { + // Again, skip any invisible segments since we don't need to navigate into + // them. + if (!cwk_path_segment_joined_skip_invisible(&osj, absolute)) { + break; + } + + // Toggle the flag if we have output. We need to remember that, since we + // want to remove the trailing slash. + has_output = true; + + // Output the current segment and a separator. No need to worry about the + // superfluous segment since it will be removed later on. + pos += cwk_path_output_sized(buffer, buffer_size, pos, osj.segment.begin, + osj.segment.size); + pos += cwk_path_output_separator(buffer, buffer_size, pos); + } while (cwk_path_get_next_segment_joined(&osj)); + } + + // If we have some output by now we will have to remove the trailing slash. We + // simply do that by moving back one character. The terminate output function + // will then place the '\0' on this position. Otherwise, if there is no + // output, we will have to output a "current directory", since the target path + // points to the base path. + if (has_output) { + --pos; + } else { + pos += cwk_path_output_current(buffer, buffer_size, pos); + } + + // Finally, we can terminate the output - which means we place a '\0' at the + // current position or at the end of the buffer. + cwk_path_terminate_output(buffer, buffer_size, pos); + + return pos; +} + +size_t cwk_path_join(const char *path_a, const char *path_b, char *buffer, + size_t buffer_size) +{ + const char *paths[3]; + + // This is simple. We will just create an array with the two paths which we + // wish to join. + paths[0] = path_a; + paths[1] = path_b; + paths[2] = NULL; + + // And then call the join and normalize function which will do the hard work + // for us. + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +size_t cwk_path_join_multiple(const char **paths, char *buffer, + size_t buffer_size) +{ + // We can just call the internal join and normalize function for this one, + // since it will handle everything. + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +void cwk_path_get_root(const char *path, size_t *length) +{ + // We use a different implementation here based on the configuration of the + // library. + if (path_style == CWK_STYLE_WINDOWS) { + cwk_path_get_root_windows(path, length); + } else { + cwk_path_get_root_unix(path, length); + } +} + +size_t cwk_path_change_root(const char *path, const char *new_root, + char *buffer, size_t buffer_size) +{ + const char *tail; + size_t root_length, path_length, tail_length, new_root_length, new_path_size; + + // First we need to determine the actual size of the root which we will + // change. + cwk_path_get_root(path, &root_length); + + // Now we determine the sizes of the new root and the path. We need that to + // determine the size of the part after the root (the tail). + new_root_length = strlen(new_root); + path_length = strlen(path); + + // Okay, now we calculate the position of the tail and the length of it. + tail = path + root_length; + tail_length = path_length - root_length; + + // We first output the tail and then the new root, that's because the source + // path and the buffer may be overlapping. This way the root will not + // overwrite the tail. + cwk_path_output_sized(buffer, buffer_size, new_root_length, tail, + tail_length); + cwk_path_output_sized(buffer, buffer_size, 0, new_root, new_root_length); + + // Finally we calculate the size o the new path and terminate the output with + // a '\0'. + new_path_size = tail_length + new_root_length; + cwk_path_terminate_output(buffer, buffer_size, new_path_size); + + return new_path_size; +} + +bool cwk_path_is_absolute(const char *path) +{ + size_t length; + + // We grab the root of the path. This root does not include the first + // separator of a path. + cwk_path_get_root(path, &length); + + // Now we can determine whether the root is absolute or not. + return cwk_path_is_root_absolute(path, length); +} + +bool cwk_path_is_relative(const char *path) +{ + // The path is relative if it is not absolute. + return !cwk_path_is_absolute(path); +} + +void cwk_path_get_basename(const char *path, const char **basename, + size_t *length) +{ + struct cwk_segment segment; + + // We get the last segment of the path. The last segment will contain the + // basename if there is any. If there are no segments we will set the basename + // to NULL and the length to 0. + if (!cwk_path_get_last_segment(path, &segment)) { + *basename = NULL; + *length = 0; + return; + } + + // Now we can just output the segment contents, since that's our basename. + // There might be trailing separators after the basename, but the size does + // not include those. + *basename = segment.begin; + *length = segment.size; +} + +size_t cwk_path_change_basename(const char *path, const char *new_basename, + char *buffer, size_t buffer_size) +{ + struct cwk_segment segment; + size_t pos, root_size, new_basename_size; + + // First we try to get the last segment. We may only have a root without any + // segments, in which case we will create one. + if (!cwk_path_get_last_segment(path, &segment)) { + + // So there is no segment in this path. First we grab the root and output + // that. We are not going to modify the root in any way. + cwk_path_get_root(path, &root_size); + pos = cwk_path_output_sized(buffer, buffer_size, 0, path, root_size); + + // We have to trim the separators from the beginning of the new basename. + // This is quite easy to do. + while (cwk_path_is_separator(new_basename)) { + ++new_basename; + } + + // Now we measure the length of the new basename, this is a two step + // process. First we find the '\0' character at the end of the string. + new_basename_size = 0; + while (new_basename[new_basename_size]) { + ++new_basename_size; + } + + // And then we trim the separators at the end of the basename until we reach + // the first valid character. + while (new_basename_size > 0 && + cwk_path_is_separator(&new_basename[new_basename_size - 1])) { + --new_basename_size; + } + + // Now we will output the new basename after the root. + pos += cwk_path_output_sized(buffer, buffer_size, pos, new_basename, + new_basename_size); + + // And finally terminate the output and return the total size of the path. + cwk_path_terminate_output(buffer, buffer_size, pos); + return pos; + } + + // If there is a last segment we can just forward this call, which is fairly + // easy. + return cwk_path_change_segment(&segment, new_basename, buffer, buffer_size); +} + +void cwk_path_get_dirname(const char *path, size_t *length) +{ + struct cwk_segment segment; + + // We get the last segment of the path. The last segment will contain the + // basename if there is any. If there are no segments we will set the length + // to 0. + if (!cwk_path_get_last_segment(path, &segment)) { + *length = 0; + return; + } + + // We can now return the length from the beginning of the string up to the + // beginning of the last segment. + *length = segment.begin - path; +} + +bool cwk_path_get_extension(const char *path, const char **extension, + size_t *length) +{ + struct cwk_segment segment; + const char *c; + + // We get the last segment of the path. The last segment will contain the + // extension if there is any. + if (!cwk_path_get_last_segment(path, &segment)) { + return false; + } + + // Now we search for a dot within the segment. If there is a dot, we consider + // the rest of the segment the extension. We do this from the end towards the + // beginning, since we want to find the last dot. + for (c = segment.end; c >= segment.begin; --c) { + if (*c == '.') { + // Okay, we found an extension. We can stop looking now. + *extension = c; + *length = segment.end - c; + return true; + } + } + + // We couldn't find any extension. + return false; +} + +bool cwk_path_has_extension(const char *path) +{ + const char *extension; + size_t length; + + // We just wrap the get_extension call which will then do the work for us. + return cwk_path_get_extension(path, &extension, &length); +} + +size_t cwk_path_change_extension(const char *path, const char *new_extension, + char *buffer, size_t buffer_size) +{ + struct cwk_segment segment; + const char *c, *old_extension; + size_t pos, root_size, trail_size, new_extension_size; + + // First we try to get the last segment. We may only have a root without any + // segments, in which case we will create one. + if (!cwk_path_get_last_segment(path, &segment)) { + + // So there is no segment in this path. First we grab the root and output + // that. We are not going to modify the root in any way. If there is no + // root, this will end up with a root size 0, and nothing will be written. + cwk_path_get_root(path, &root_size); + pos = cwk_path_output_sized(buffer, buffer_size, 0, path, root_size); + + // Add a dot if the submitted value doesn't have any. + if (*new_extension != '.') { + pos += cwk_path_output_dot(buffer, buffer_size, pos); + } + + // And finally terminate the output and return the total size of the path. + pos += cwk_path_output(buffer, buffer_size, pos, new_extension); + cwk_path_terminate_output(buffer, buffer_size, pos); + return pos; + } + + // Now we seek the old extension in the last segment, which we will replace + // with the new one. If there is no old extension, it will point to the end of + // the segment. + old_extension = segment.end; + for (c = segment.begin; c < segment.end; ++c) { + if (*c == '.') { + old_extension = c; + } + } + + pos = cwk_path_output_sized(buffer, buffer_size, 0, segment.path, + old_extension - segment.path); + + // If the new extension starts with a dot, we will skip that dot. We always + // output exactly one dot before the extension. If the extension contains + // multiple dots, we will output those as part of the extension. + if (*new_extension == '.') { + ++new_extension; + } + + // We calculate the size of the new extension, including the dot, in order to + // output the trail - which is any part of the path coming after the + // extension. We must output this first, since the buffer may overlap with the + // submitted path - and it would be overridden by longer extensions. + new_extension_size = strlen(new_extension) + 1; + trail_size = cwk_path_output(buffer, buffer_size, pos + new_extension_size, + segment.end); + + // Finally we output the dot and the new extension. The new extension itself + // doesn't contain the dot anymore, so we must output that first. + pos += cwk_path_output_dot(buffer, buffer_size, pos); + pos += cwk_path_output(buffer, buffer_size, pos, new_extension); + + // Now we terminate the output with a null-terminating character, but before + // we do that we must add the size of the trail to the position which we + // output before. + pos += trail_size; + cwk_path_terminate_output(buffer, buffer_size, pos); + + // And the position is our output size now. + return pos; +} + +size_t cwk_path_normalize(const char *path, char *buffer, size_t buffer_size) +{ + const char *paths[2]; + + // Now we initialize the paths which we will normalize. Since this function + // only supports submitting a single path, we will only add that one. + paths[0] = path; + paths[1] = NULL; + + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +size_t cwk_path_get_intersection(const char *path_base, const char *path_other) +{ + bool absolute; + size_t base_root_length, other_root_length; + const char *end; + const char *paths_base[2], *paths_other[2]; + struct cwk_segment_joined base, other; + + // We first compare the two roots. We just return zero if they are not equal. + // This will also happen to return zero if the paths are mixed relative and + // absolute. + cwk_path_get_root(path_base, &base_root_length); + cwk_path_get_root(path_other, &other_root_length); + if (!cwk_path_is_string_equal(path_base, path_other, base_root_length)) { + return 0; + } + + // Configure our paths. We just have a single path in here for now. + paths_base[0] = path_base; + paths_base[1] = NULL; + paths_other[0] = path_other; + paths_other[1] = NULL; + + // So we get the first segment of both paths. If one of those paths don't have + // any segment, we will return 0. + if (!cwk_path_get_first_segment_joined(paths_base, &base) || + !cwk_path_get_first_segment_joined(paths_other, &other)) { + return base_root_length; + } + + // We now determine whether the path is absolute or not. This is required + // because if will ignore removed segments, and this behaves differently if + // the path is absolute. However, we only need to check the base path because + // we are guaranteed that both paths are either relative or absolute. + absolute = cwk_path_is_root_absolute(path_base, base_root_length); + + // We must keep track of the end of the previous segment. Initially, this is + // set to the beginning of the path. This means that 0 is returned if the + // first segment is not equal. + end = path_base + base_root_length; + + // Now we loop over both segments until one of them reaches the end or their + // contents are not equal. + do { + // We skip all segments which will be removed in each path, since we want to + // know about the true path. + if (!cwk_path_segment_joined_skip_invisible(&base, absolute) || + !cwk_path_segment_joined_skip_invisible(&other, absolute)) { + break; + } + + if (!cwk_path_is_string_equal(base.segment.begin, other.segment.begin, + base.segment.size)) { + // So the content of those two segments are not equal. We will return the + // size up to the beginning. + return end - path_base; + } + + // Remember the end of the previous segment before we go to the next one. + end = base.segment.end; + } while (cwk_path_get_next_segment_joined(&base) && + cwk_path_get_next_segment_joined(&other)); + + // Now we calculate the length up to the last point where our paths pointed to + // the same place. + return end - path_base; +} + +bool cwk_path_get_first_segment(const char *path, struct cwk_segment *segment) +{ + size_t length; + const char *segments; + + // We skip the root since that's not part of the first segment. The root is + // treated as a separate entity. + cwk_path_get_root(path, &length); + segments = path + length; + + // Now, after we skipped the root we can continue and find the actual segment + // content. + return cwk_path_get_first_segment_without_root(path, segments, segment); +} + +bool cwk_path_get_last_segment(const char *path, struct cwk_segment *segment) +{ + // We first grab the first segment. This might be our last segment as well, + // but we don't know yet. There is no last segment if there is no first + // segment, so we return false in that case. + if (!cwk_path_get_first_segment(path, segment)) { + return false; + } + + // Now we find our last segment. The segment struct of the caller + // will contain the last segment, since the function we call here will not + // change the segment struct when it reaches the end. + while (cwk_path_get_next_segment(segment)) { + // We just loop until there is no other segment left. + } + + return true; +} + +bool cwk_path_get_next_segment(struct cwk_segment *segment) +{ + const char *c; + + // First we jump to the end of the previous segment. The first character must + // be either a '\0' or a separator. + c = segment->begin + segment->size; + if (*c == '\0') { + return false; + } + + // Now we skip all separator until we reach something else. We are not yet + // guaranteed to have a segment, since the string could just end afterwards. + assert(cwk_path_is_separator(c)); + do { + ++c; + } while (cwk_path_is_separator(c)); + + // If the string ends here, we can safely assume that there is no other + // segment after this one. + if (*c == '\0') { + return false; + } + + // Now we are safe to assume there is a segment. We store the beginning of + // this segment in the segment struct of the caller. + segment->begin = c; + + // And now determine the size of this segment, and store it in the struct of + // the caller as well. + c = cwk_path_find_next_stop(c); + segment->end = c; + segment->size = c - segment->begin; + + // Tell the caller that we found a segment. + return true; +} + +bool cwk_path_get_previous_segment(struct cwk_segment *segment) +{ + const char *c; + + // The current position might point to the first character of the path, which + // means there are no previous segments available. + c = segment->begin; + if (c <= segment->segments) { + return false; + } + + // We move towards the beginning of the path until we either reached the + // beginning or the character is no separator anymore. + do { + --c; + if (c <= segment->segments) { + // So we reached the beginning here and there is no segment. So we return + // false and don't change the segment structure submitted by the caller. + return false; + } + } while (cwk_path_is_separator(c)); + + // We are guaranteed now that there is another segment, since we moved before + // the previous separator and did not reach the segment path beginning. + segment->end = c + 1; + segment->begin = cwk_path_find_previous_stop(segment->segments, c); + segment->size = segment->end - segment->begin; + + return true; +} + +enum cwk_segment_type cwk_path_get_segment_type( + const struct cwk_segment *segment) +{ + // We just make a string comparison with the segment contents and return the + // appropriate type. + if (strncmp(segment->begin, ".", segment->size) == 0) { + return CWK_CURRENT; + } else if (strncmp(segment->begin, "..", segment->size) == 0) { + return CWK_BACK; + } + + return CWK_NORMAL; +} + +bool cwk_path_is_separator(const char *str) +{ + const char *c; + + // We loop over all characters in the read symbols. + c = separators[path_style]; + while (*c) { + if (*c == *str) { + return true; + } + + ++c; + } + + return false; +} + +size_t cwk_path_change_segment(struct cwk_segment *segment, const char *value, + char *buffer, size_t buffer_size) +{ + size_t pos, value_size, tail_size; + + // First we have to output the head, which is the whole string up to the + // beginning of the segment. This part of the path will just stay the same. + pos = cwk_path_output_sized(buffer, buffer_size, 0, segment->path, + segment->begin - segment->path); + + // In order to trip the submitted value, we will skip any separator at the + // beginning of it and behave as if it was never there. + while (cwk_path_is_separator(value)) { + ++value; + } + + // Now we determine the length of the value. In order to do that we first + // locate the '\0'. + value_size = 0; + while (value[value_size]) { + ++value_size; + } + + // Since we trim separators at the beginning and in the end of the value we + // have to subtract from the size until there are either no more characters + // left or the last character is no separator. + while (value_size > 0 && cwk_path_is_separator(&value[value_size - 1])) { + --value_size; + } + + // We also have to determine the tail size, which is the part of the string + // following the current segment. This part will not change. + tail_size = strlen(segment->end); + + // Now we output the tail. We have to do that, because if the buffer and the + // source are overlapping we would override the tail if the value is + // increasing in length. + cwk_path_output_sized(buffer, buffer_size, pos + value_size, segment->end, + tail_size); + + // Finally we can output the value in the middle of the head and the tail, + // where we have enough space to fit the whole trimmed value. + pos += cwk_path_output_sized(buffer, buffer_size, pos, value, value_size); + + // Now we add the tail size to the current position and terminate the output - + // basically, ensure that there is a '\0' at the end of the buffer. + pos += tail_size; + cwk_path_terminate_output(buffer, buffer_size, pos); + + // And now tell the caller how long the whole path would be. + return pos; +} + +enum cwk_path_style cwk_path_guess_style(const char *path) +{ + const char *c; + size_t root_length; + struct cwk_segment segment; + + // First we determine the root. Only windows roots can be longer than a single + // slash, so if we can determine that it starts with something like "C:", we + // know that this is a windows path. + cwk_path_get_root_windows(path, &root_length); + if (root_length > 1) { + return CWK_STYLE_WINDOWS; + } + + // Next we check for slashes. Windows uses backslashes, while unix uses + // forward slashes. Windows actually supports both, but our best guess is to + // assume windows with backslashes and unix with forward slashes. + for (c = path; *c; ++c) { + if (*c == *separators[CWK_STYLE_UNIX]) { + return CWK_STYLE_UNIX; + } else if (*c == *separators[CWK_STYLE_WINDOWS]) { + return CWK_STYLE_WINDOWS; + } + } + + // This path does not have any slashes. We grab the last segment (which + // actually must be the first one), and determine whether the segment starts + // with a dot. A dot is a hidden folder or file in the UNIX world, in that + // case we assume the path to have UNIX style. + if (!cwk_path_get_last_segment(path, &segment)) { + // We couldn't find any segments, so we default to a UNIX path style since + // there is no way to make any assumptions. + return CWK_STYLE_UNIX; + } + + if (*segment.begin == '.') { + return CWK_STYLE_UNIX; + } + + // And finally we check whether the last segment contains a dot. If it + // contains a dot, that might be an extension. Windows is more likely to have + // file names with extensions, so our guess would be windows. + for (c = segment.begin; *c; ++c) { + if (*c == '.') { + return CWK_STYLE_WINDOWS; + } + } + + // All our checks failed, so we will return a default value which is currently + // UNIX. + return CWK_STYLE_UNIX; +} + +void cwk_path_set_style(enum cwk_path_style style) +{ + // We can just set the global path style variable and then the behaviour for + // all functions will change accordingly. + assert(style == CWK_STYLE_UNIX || style == CWK_STYLE_WINDOWS); + path_style = style; +} + +enum cwk_path_style cwk_path_get_style(void) +{ + // Simply return the path style which we store in a global variable. + return path_style; +} diff --git a/src/disk/minivhd/cwalk.h b/src/disk/minivhd/cwalk.h new file mode 100644 index 000000000..baa5d432d --- /dev/null +++ b/src/disk/minivhd/cwalk.h @@ -0,0 +1,457 @@ +#pragma once + +#ifndef CWK_LIBRARY_H +#define CWK_LIBRARY_H + +#include +#include + +/** + * A segment represents a single component of a path. For instance, on linux a + * path might look like this "/var/log/", which consists of two segments "var" + * and "log". + */ +struct cwk_segment +{ + const char *path; + const char *segments; + const char *begin; + const char *end; + size_t size; +}; + +/** + * The segment type can be used to identify whether a segment is a special + * segment or not. + * + * CWK_NORMAL - normal folder or file segment + * CWK_CURRENT - "./" current folder segment + * CWK_BACK - "../" relative back navigation segment + */ +enum cwk_segment_type +{ + CWK_NORMAL, + CWK_CURRENT, + CWK_BACK +}; + +/** + * @brief Determines the style which is used for the path parsing and + * generation. + */ +enum cwk_path_style +{ + CWK_STYLE_WINDOWS, + CWK_STYLE_UNIX +}; + +/** + * @brief Generates an absolute path based on a base. + * + * This function generates an absolute path based on a base path and another + * path. It is guaranteed to return an absolute path. If the second submitted + * path is absolute, it will override the base path. The result will be written + * to a buffer, which might be truncated if the buffer is not large enough to + * hold the full path. However, the truncated result will always be + * null-terminated. The returned value is the amount of characters which the + * resulting path would take if it was not truncated (excluding the + * null-terminating character). + * + * @param base The base path on which the relative path will be applied. + * @param path The relative path which will be applied on the base path. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the new absolute path. + */ +size_t cwk_path_get_absolute(const char *base, const char *path, char *buffer, + size_t buffer_size); + +/** + * @brief Generates a relative path based on a base. + * + * This function generates a relative path based on a base path and another + * path. It determines how to get to the submitted path, starting from the base + * directory. The result will be written to a buffer, which might be truncated + * if the buffer is not large enough to hold the full path. However, the + * truncated result will always be null-terminated. The returned value is the + * amount of characters which the resulting path would take if it was not + * truncated (excluding the null-terminating character). + * + * @param base_directory The base path from which the relative path will start. + * @param path The target path where the relative path will point to. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the full path. + */ +size_t cwk_path_get_relative(const char *base_directory, const char *path, + char *buffer, size_t buffer_size); + +/** + * @brief Joins two paths together. + * + * This function generates a new path by combining the two submitted paths. It + * will remove double separators, and unlike cwk_path_get_absolute it permits + * the use of two relative paths to combine. The result will be written to a + * buffer, which might be truncated if the buffer is not large enough to hold + * the full path. However, the truncated result will always be null-terminated. + * The returned value is the amount of characters which the resulting path would + * take if it was not truncated (excluding the null-terminating character). + * + * @param path_a The first path which comes first. + * @param path_b The second path which comes after the first. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the full, combined path. + */ +size_t cwk_path_join(const char *path_a, const char *path_b, char *buffer, + size_t buffer_size); + +/** + * @brief Joins multiple paths together. + * + * This function generates a new path by joining multiple paths together. It + * will remove double separators, and unlike cwk_path_get_absolute it permits + * the use of multiple relative paths to combine. The last path of the submitted + * string array must be set to NULL. The result will be written to a buffer, + * which might be truncated if the buffer is not large enough to hold the full + * path. However, the truncated result will always be null-terminated. The + * returned value is the amount of characters which the resulting path would + * take if it was not truncated (excluding the null-terminating character). + * + * @param paths An array of paths which will be joined. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the full, combined path. + */ +size_t cwk_path_join_multiple(const char **paths, char *buffer, + size_t buffer_size); + +/** + * @brief Determines the root of a path. + * + * This function determines the root of a path by finding it's length. The root + * always starts at the submitted path. If the path has no root, the length will + * be set to zero. + * + * @param path The path which will be inspected. + * @param length The output of the root length. + */ +void cwk_path_get_root(const char *path, size_t *length); + +/** + * @brief Changes the root of a path. + * + * This function changes the root of a path. It does not normalize the result. + * The result will be written to a buffer, which might be truncated if the + * buffer is not large enough to hold the full path. However, the truncated + * result will always be null-terminated. The returned value is the amount of + * characters which the resulting path would take if it was not truncated + * (excluding the null-terminating character). + * + * @param path The original path which will get a new root. + * @param new_root The new root which will be placed in the path. + * @param buffer The output buffer where the result is written to. + * @param buffer_size The size of the output buffer where the result is written + * to. + * @return Returns the total amount of characters of the new path. + */ +size_t cwk_path_change_root(const char *path, const char *new_root, + char *buffer, size_t buffer_size); + +/** + * @brief Determine whether the path is absolute or not. + * + * This function checks whether the path is an absolute path or not. A path is + * considered to be absolute if the root ends with a separator. + * + * @param path The path which will be checked. + * @return Returns true if the path is absolute or false otherwise. + */ +bool cwk_path_is_absolute(const char *path); + +/** + * @brief Determine whether the path is relative or not. + * + * This function checks whether the path is a relative path or not. A path is + * considered to be relative if the root does not end with a separator. + * + * @param path The path which will be checked. + * @return Returns true if the path is relative or false otherwise. + */ +bool cwk_path_is_relative(const char *path); + +/** + * @brief Gets the basename of a file path. + * + * This function gets the basename of a file path. A pointer to the beginning of + * the basename will be returned through the basename parameter. This pointer + * will be positioned on the first letter after the separator. The length of the + * file path will be returned through the length parameter. The length will be + * set to zero and the basename to NULL if there is no basename available. + * + * @param path The path which will be inspected. + * @param basename The output of the basename pointer. + * @param length The output of the length of the basename. + */ +void cwk_path_get_basename(const char *path, const char **basename, + size_t *length); + +/** + * @brief Changes the basename of a file path. + * + * This function changes the basename of a file path. This function will not + * write out more than the specified buffer can contain. However, the generated + * string is always null-terminated - even if not the whole path is written out. + * The function returns the total number of characters the complete buffer would + * have, even if it was not written out completely. The path may be the same + * memory address as the buffer. + * + * @param path The original path which will be used for the modified path. + * @param new_basename The new basename which will replace the old one. + * @param buffer The buffer where the changed path will be written to. + * @param buffer_size The size of the result buffer where the changed path is + * written to. + * @return Returns the size which the complete new path would have if it was not + * truncated. + */ +size_t cwk_path_change_basename(const char *path, const char *new_basename, + char *buffer, size_t buffer_size); + +/** + * @brief Gets the dirname of a file path. + * + * This function determines the dirname of a file path and returns the length up + * to which character is considered to be part of it. If no dirname is found, + * the length will be set to zero. The beginning of the dirname is always equal + * to the submitted path pointer. + * + * @param path The path which will be inspected. + * @param length The length of the dirname. + */ +void cwk_path_get_dirname(const char *path, size_t *length); + +/** + * @brief Gets the extension of a file path. + * + * This function extracts the extension portion of a file path. A pointer to + * the beginning of the extension will be returned through the extension + * parameter if an extension is found and true is returned. This pointer will be + * positioned on the dot. The length of the extension name will be returned + * through the length parameter. If no extension is found both parameters won't + * be touched and false will be returned. + * + * @param path The path which will be inspected. + * @param extension The output of the extension pointer. + * @param length The output of the length of the extension. + * @return Returns true if an extension is found or false otherwise. + */ +bool cwk_path_get_extension(const char *path, const char **extension, + size_t *length); + +/** + * @brief Determines whether the file path has an extension. + * + * This function determines whether the submitted file path has an extension. + * This will evaluate to true if the last segment of the path contains a dot. + * + * @param path The path which will be inspected. + * @return Returns true if the path has an extension or false otherwise. + */ +bool cwk_path_has_extension(const char *path); + +/** + * @brief Changes the extension of a file path. + * + * This function changes the extension of a file name. The function will append + * an extension if the basename does not have an extension, or use the extension + * as a basename if the path does not have a basename. This function will not + * write out more than the specified buffer can contain. However, the generated + * string is always null-terminated - even if not the whole path is written out. + * The function returns the total number of characters the complete buffer would + * have, even if it was not written out completely. The path may be the same + * memory address as the buffer. + * + * @param path The path which will be used to make the change. + * @param new_extension The extension which will be placed within the new path. + * @param buffer The output buffer where the result will be written to. + * @param buffer_size The size of the output buffer where the result will be + * written to. + * @return Returns the total size which the output would have if it was not + * truncated. + */ +size_t cwk_path_change_extension(const char *path, const char *new_extension, + char *buffer, size_t buffer_size); + +/** + * @brief Creates a normalized version of the path. + * + * This function creates a normalized version of the path within the specified + * buffer. This function will not write out more than the specified buffer can + * contain. However, the generated string is always null-terminated - even if + * not the whole path is written out. The function returns the total number of + * characters the complete buffer would have, even if it was not written out + * completely. The path may be the same memory address as the buffer. + * + * The following will be true for the normalized path: + * 1) "../" will be resolved. + * 2) "./" will be removed. + * 3) double separators will be fixed with a single separator. + * 4) separator suffixes will be removed. + * + * @param path The path which will be normalized. + * @param buffer The buffer where the new path is written to. + * @param buffer_size The size of the buffer. + * @return The size which the complete normalized path has if it was not + * truncated. + */ +size_t cwk_path_normalize(const char *path, char *buffer, size_t buffer_size); + +/** + * @brief Finds common portions in two paths. + * + * This function finds common portions in two paths and returns the number + * characters from the beginning of the base path which are equal to the other + * path. + * + * @param path_base The base path which will be compared with the other path. + * @param path_other The other path which will compared with the base path. + * @return Returns the number of characters which are common in the base path. + */ +size_t cwk_path_get_intersection(const char *path_base, const char *path_other); + +/** + * @brief Gets the first segment of a path. + * + * This function finds the first segment of a path. The position of the segment + * is set to the first character after the separator, and the length counts all + * characters until the next separator (excluding the separator). + * + * @param path The path which will be inspected. + * @param segment The segment which will be extracted. + * @return Returns true if there is a segment or false if there is none. + */ +bool cwk_path_get_first_segment(const char *path, struct cwk_segment *segment); + +/** + * @brief Gets the last segment of the path. + * + * This function gets the last segment of a path. This function may return false + * if the path doesn't contain any segments, in which case the submitted segment + * parameter is not modified. The position of the segment is set to the first + * character after the separator, and the length counts all characters until the + * end of the path (excluding the separator). + * + * @param path The path which will be inspected. + * @param segment The segment which will be extracted. + * @return Returns true if there is a segment or false if there is none. + */ +bool cwk_path_get_last_segment(const char *path, struct cwk_segment *segment); + +/** + * @brief Advances to the next segment. + * + * This function advances the current segment to the next segment. If there are + * no more segments left, the submitted segment structure will stay unchanged + * and false is returned. + * + * @param segment The current segment which will be advanced to the next one. + * @return Returns true if another segment was found or false otherwise. + */ +bool cwk_path_get_next_segment(struct cwk_segment *segment); + +/** + * @brief Moves to the previous segment. + * + * This function moves the current segment to the previous segment. If the + * current segment is the first one, the submitted segment structure will stay + * unchanged and false is returned. + * + * @param segment The current segment which will be moved to the previous one. + * @return Returns true if there is a segment before this one or false + * otherwise. + */ +bool cwk_path_get_previous_segment(struct cwk_segment *segment); + +/** + * @brief Gets the type of the submitted path segment. + * + * This function inspects the contents of the segment and determines the type of + * it. Currently, there are three types CWK_NORMAL, CWK_CURRENT and CWK_BACK. A + * CWK_NORMAL segment is a normal folder or file entry. A CWK_CURRENT is a "./" + * and a CWK_BACK a "../" segment. + * + * @param segment The segment which will be inspected. + * @return Returns the type of the segment. + */ +enum cwk_segment_type cwk_path_get_segment_type( + const struct cwk_segment *segment); + +/** + * @brief Changes the content of a segment. + * + * This function overrides the content of a segment to the submitted value and + * outputs the whole new path to the submitted buffer. The result might require + * less or more space than before if the new value length differs from the + * original length. The output is truncated if the new path is larger than the + * submitted buffer size, but it is always null-terminated. The source of the + * segment and the submitted buffer may be the same. + * + * @param segment The segment which will be modifier. + * @param value The new content of the segment. + * @param buffer The buffer where the modified path will be written to. + * @param buffer_size The size of the output buffer. + * @return Returns the total size which would have been written if the output + * was not truncated. + */ +size_t cwk_path_change_segment(struct cwk_segment *segment, const char *value, + char *buffer, size_t buffer_size); + +/** + * @brief Checks whether the submitted pointer points to a separator. + * + * This function simply checks whether the submitted pointer points to a + * separator, which has to be null-terminated (but not necessarily after the + * separator). The function will return true if it is a separator, or false + * otherwise. + * + * @param symbol A pointer to a string. + * @return Returns true if it is a separator, or false otherwise. + */ +bool cwk_path_is_separator(const char *str); + +/** + * @brief Guesses the path style. + * + * This function guesses the path style based on a submitted path-string. The + * guessing will look at the root and the type of slashes contained in the path + * and return the style which is more likely used in the path. + * + * @param path The path which will be inspected. + * @return Returns the style which is most likely used for the path. + */ +enum cwk_path_style cwk_path_guess_style(const char *path); + +/** + * @brief Configures which path style is used. + * + * This function configures which path style is used. The following styles are + * currently supported. + * + * CWK_STYLE_WINDOWS: Use backslashes as a separator and volume for the root. + * CWK_STYLE_UNIX: Use slashes as a separator and a slash for the root. + * + * @param style The style which will be used from now on. + */ +void cwk_path_set_style(enum cwk_path_style style); + +/** + * @brief Gets the path style configuration. + * + * This function gets the style configuration which is currently used for the + * paths. This configuration determines how paths are parsed and generated. + * + * @return Returns the current path style configuration. + */ +enum cwk_path_style cwk_path_get_style(void); + +#endif diff --git a/src/disk/minivhd/libxml2_encoding.c b/src/disk/minivhd/libxml2_encoding.c new file mode 100644 index 000000000..cb881a89b --- /dev/null +++ b/src/disk/minivhd/libxml2_encoding.c @@ -0,0 +1,447 @@ +/* + * encoding.c : implements the encoding conversion functions needed for XML + * + * Related specs: + * rfc2044 (UTF-8 and UTF-16) F. Yergeau Alis Technologies + * rfc2781 UTF-16, an encoding of ISO 10646, P. Hoffman, F. Yergeau + * [ISO-10646] UTF-8 and UTF-16 in Annexes + * [ISO-8859-1] ISO Latin-1 characters codes. + * [UNICODE] The Unicode Consortium, "The Unicode Standard -- + * Worldwide Character Encoding -- Version 1.0", Addison- + * Wesley, Volume 1, 1991, Volume 2, 1992. UTF-8 is + * described in Unicode Technical Report #4. + * [US-ASCII] Coded Character Set--7-bit American Standard Code for + * Information Interchange, ANSI X3.4-1986. + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + * + * Original code for IsoLatin1 and UTF-16 by "Martin J. Duerst" + * + * Adapted and abridged for MiniVHD by Sherman Perry + */ +#include + +static int xmlLittleEndian = 1; + +/* Note: extracted from original 'void xmlInitCharEncodingHandlers(void)' function */ +void xmlEncodingInit(void) +{ + unsigned short int tst = 0x1234; + unsigned char *ptr = (unsigned char *) &tst; + + if (*ptr == 0x12) xmlLittleEndian = 0; + else if (*ptr == 0x34) xmlLittleEndian = 1; +} + +/** + * UTF16LEToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @inb: a pointer to an array of UTF-16LE passwd as a byte array + * @inlenb: the length of @in in UTF-16LE chars + * + * Take a block of UTF-16LE ushorts in and try to convert it to an UTF-8 + * block of chars out. This function assumes the endian property + * is the same between the native type of this machine and the + * inputed one. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding fails (if *in is not a valid utf16 string) + * The value of *inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + */ +int UTF16LEToUTF8(unsigned char* out, int *outlen, + const unsigned char* inb, int *inlenb) +{ + unsigned char* outstart = out; + const unsigned char* processed = inb; + unsigned char* outend = out + *outlen; + unsigned short* in = (unsigned short*) inb; + unsigned short* inend; + unsigned int c, d, inlen; + unsigned char *tmp; + int bits; + + if ((*inlenb % 2) == 1) + (*inlenb)--; + inlen = *inlenb / 2; + inend = in + inlen; + while ((in < inend) && (out - outstart + 5 < *outlen)) { + if (xmlLittleEndian) { + c= *in++; + } else { + tmp = (unsigned char *) in; + c = *tmp++; + c = c | (((unsigned int)*tmp) << 8); + in++; + } + if ((c & 0xFC00) == 0xD800) { /* surrogates */ + if (in >= inend) { /* (in > inend) shouldn't happens */ + break; + } + if (xmlLittleEndian) { + d = *in++; + } else { + tmp = (unsigned char *) in; + d = *tmp++; + d = d | (((unsigned int)*tmp) << 8); + in++; + } + if ((d & 0xFC00) == 0xDC00) { + c &= 0x03FF; + c <<= 10; + c |= d & 0x03FF; + c += 0x10000; + } + else { + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + } + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) { *out++= c; bits= -6; } + else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; } + else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; } + else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; } + + for ( ; bits >= 0; bits-= 6) { + if (out >= outend) + break; + *out++= ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char*) in; + } + *outlen = out - outstart; + *inlenb = processed - inb; + return(*outlen); +} + +/** + * UTF8ToUTF16LE: + * @outb: a pointer to an array of bytes to store the result + * @outlen: the length of @outb + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an UTF-16LE + * block of chars out. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding failed. + */ +int UTF8ToUTF16LE(unsigned char* outb, int *outlen, + const unsigned char* in, int *inlen) +{ + unsigned short* out = (unsigned short*) outb; + const unsigned char* processed = in; + const unsigned char *const instart = in; + unsigned short* outstart= out; + unsigned short* outend; + const unsigned char* inend; + unsigned int c, d; + int trailing; + unsigned char *tmp; + unsigned short tmp1, tmp2; + + /* UTF16LE encoding has no BOM */ + if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + *outlen = 0; + *inlen = 0; + return(0); + } + inend= in + *inlen; + outend = out + (*outlen / 2); + while (in < inend) { + d= *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in UTF-16 */ + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) + break; + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c < 0x10000) { + if (out >= outend) + break; + if (xmlLittleEndian) { + *out++ = c; + } else { + tmp = (unsigned char *) out; + *tmp = c ; + *(tmp + 1) = c >> 8 ; + out++; + } + } + else if (c < 0x110000) { + if (out+1 >= outend) + break; + c -= 0x10000; + if (xmlLittleEndian) { + *out++ = 0xD800 | (c >> 10); + *out++ = 0xDC00 | (c & 0x03FF); + } else { + tmp1 = 0xD800 | (c >> 10); + tmp = (unsigned char *) out; + *tmp = (unsigned char) tmp1; + *(tmp + 1) = tmp1 >> 8; + out++; + + tmp2 = 0xDC00 | (c & 0x03FF); + tmp = (unsigned char *) out; + *tmp = (unsigned char) tmp2; + *(tmp + 1) = tmp2 >> 8; + out++; + } + } + else + break; + processed = in; + } + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(*outlen); +} + +/** + * UTF16BEToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @inb: a pointer to an array of UTF-16 passed as a byte array + * @inlenb: the length of @in in UTF-16 chars + * + * Take a block of UTF-16 ushorts in and try to convert it to an UTF-8 + * block of chars out. This function assumes the endian property + * is the same between the native type of this machine and the + * inputed one. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding fails (if *in is not a valid utf16 string) + * The value of *inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + */ +int UTF16BEToUTF8(unsigned char* out, int *outlen, + const unsigned char* inb, int *inlenb) +{ + unsigned char* outstart = out; + const unsigned char* processed = inb; + unsigned char* outend = out + *outlen; + unsigned short* in = (unsigned short*) inb; + unsigned short* inend; + unsigned int c, d, inlen; + unsigned char *tmp; + int bits; + + if ((*inlenb % 2) == 1) + (*inlenb)--; + inlen = *inlenb / 2; + inend= in + inlen; + while (in < inend) { + if (xmlLittleEndian) { + tmp = (unsigned char *) in; + c = *tmp++; + c = c << 8; + c = c | (unsigned int) *tmp; + in++; + } else { + c= *in++; + } + if ((c & 0xFC00) == 0xD800) { /* surrogates */ + if (in >= inend) { /* (in > inend) shouldn't happens */ + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + if (xmlLittleEndian) { + tmp = (unsigned char *) in; + d = *tmp++; + d = d << 8; + d = d | (unsigned int) *tmp; + in++; + } else { + d= *in++; + } + if ((d & 0xFC00) == 0xDC00) { + c &= 0x03FF; + c <<= 10; + c |= d & 0x03FF; + c += 0x10000; + } + else { + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + } + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) { *out++= c; bits= -6; } + else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; } + else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; } + else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; } + + for ( ; bits >= 0; bits-= 6) { + if (out >= outend) + break; + *out++= ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char*) in; + } + *outlen = out - outstart; + *inlenb = processed - inb; + return(*outlen); +} + +/** + * UTF8ToUTF16BE: + * @outb: a pointer to an array of bytes to store the result + * @outlen: the length of @outb + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an UTF-16BE + * block of chars out. + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + */ +int UTF8ToUTF16BE(unsigned char* outb, int *outlen, + const unsigned char* in, int *inlen) +{ + unsigned short* out = (unsigned short*) outb; + const unsigned char* processed = in; + const unsigned char *const instart = in; + unsigned short* outstart= out; + unsigned short* outend; + const unsigned char* inend; + unsigned int c, d; + int trailing; + unsigned char *tmp; + unsigned short tmp1, tmp2; + + /* UTF-16BE has no BOM */ + if ((outb == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + *outlen = 0; + *inlen = 0; + return(0); + } + inend= in + *inlen; + outend = out + (*outlen / 2); + while (in < inend) { + d= *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in UTF-16 */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) break; + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c < 0x10000) { + if (out >= outend) break; + if (xmlLittleEndian) { + tmp = (unsigned char *) out; + *tmp = c >> 8; + *(tmp + 1) = c; + out++; + } else { + *out++ = c; + } + } + else if (c < 0x110000) { + if (out+1 >= outend) break; + c -= 0x10000; + if (xmlLittleEndian) { + tmp1 = 0xD800 | (c >> 10); + tmp = (unsigned char *) out; + *tmp = tmp1 >> 8; + *(tmp + 1) = (unsigned char) tmp1; + out++; + + tmp2 = 0xDC00 | (c & 0x03FF); + tmp = (unsigned char *) out; + *tmp = tmp2 >> 8; + *(tmp + 1) = (unsigned char) tmp2; + out++; + } else { + *out++ = 0xD800 | (c >> 10); + *out++ = 0xDC00 | (c & 0x03FF); + } + } + else + break; + processed = in; + } + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(*outlen); +} + +/* This file is licenced under the MIT licence as follows: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ \ No newline at end of file diff --git a/src/disk/minivhd/libxml2_encoding.h b/src/disk/minivhd/libxml2_encoding.h new file mode 100644 index 000000000..831aea4af --- /dev/null +++ b/src/disk/minivhd/libxml2_encoding.h @@ -0,0 +1,12 @@ +#ifndef LIBXML2_ENCODING_H +#define LIBXML2_ENCODING_H + +#include +typedef uint16_t mvhd_utf16; + +void xmlEncodingInit(void); +int UTF16LEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb); +int UTF8ToUTF16LE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen); +int UTF16BEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb); +int UTF8ToUTF16BE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen); +#endif \ No newline at end of file diff --git a/src/disk/minivhd/minivhd.h b/src/disk/minivhd/minivhd.h new file mode 100644 index 000000000..0d925f71a --- /dev/null +++ b/src/disk/minivhd/minivhd.h @@ -0,0 +1,269 @@ +#ifndef MINIVHD_H +#define MINIVHD_H + +#include +#include +#include + +extern int mvhd_errno; + +typedef enum MVHDError { + MVHD_ERR_MEM = -128, + MVHD_ERR_FILE, + MVHD_ERR_NOT_VHD, + MVHD_ERR_TYPE, + MVHD_ERR_FOOTER_CHECKSUM, + MVHD_ERR_SPARSE_CHECKSUM, + MVHD_ERR_UTF_TRANSCODING_FAILED, + MVHD_ERR_UTF_SIZE, + MVHD_ERR_PATH_REL, + MVHD_ERR_PATH_LEN, + MVHD_ERR_PAR_NOT_FOUND, + MVHD_ERR_INVALID_PAR_UUID, + MVHD_ERR_INVALID_GEOM, + MVHD_ERR_INVALID_SIZE, + MVHD_ERR_INVALID_BLOCK_SIZE, + MVHD_ERR_INVALID_PARAMS, + MVHD_ERR_CONV_SIZE, + MVHD_ERR_TIMESTAMP +} MVHDError; + +typedef enum MVHDType { + MVHD_TYPE_FIXED = 2, + MVHD_TYPE_DYNAMIC = 3, + MVHD_TYPE_DIFF = 4 +} MVHDType; + +typedef enum MVHDBlockSize { + MVHD_BLOCK_DEFAULT = 0, /**< 2 MB blocks */ + MVHD_BLOCK_SMALL = 1024, /**< 512 KB blocks */ + MVHD_BLOCK_LARGE = 4096 /**< 2 MB blocks */ +} MVHDBlockSize; + +typedef struct MVHDGeom { + uint16_t cyl; + uint8_t heads; + uint8_t spt; +} MVHDGeom; + +typedef void (*mvhd_progress_callback)(uint32_t current_sector, uint32_t total_sectors); + +typedef struct MVHDCreationOptions { + int type; /** MVHD_TYPE_FIXED, MVHD_TYPE_DYNAMIC, or MVHD_TYPE_DIFF */ + char* path; /** Absolute path of the new VHD file */ + char* parent_path; /** For MVHD_TYPE_DIFF, this is the absolute path of the VHD's parent. For non-diff VHDs, this should be NULL. */ + uint64_t size_in_bytes; /** Total size of the VHD's virtual disk in bytes. Must be a multiple of 512. If 0, the size is auto-calculated from the geometry field. Ignored for MVHD_TYPE_DIFF. */ + MVHDGeom geometry; /** The geometry of the VHD. If set to 0, the geometry is auto-calculated from the size_in_bytes field. */ + uint32_t block_size_in_sectors; /** MVHD_BLOCK_LARGE or MVHD_BLOCK_SMALL, or 0 for the default value. The number of sectors per block. */ + mvhd_progress_callback progress_callback; /** Optional; if not NULL, gets called to indicate progress on the creation operation. Only applies to MVHD_TYPE_FIXED. */ +} MVHDCreationOptions; + +typedef struct MVHDMeta MVHDMeta; + +/** + * \brief Output a string from a MiniVHD error number + * + * \param [in] err is the error number to return string from + * + * \return Error string + */ +const char* mvhd_strerr(MVHDError err); + +/** + * \brief A simple test to see if a given file is a VHD + * + * \param [in] f file to test + * + * \retval true if f is a VHD + * \retval false if f is not a VHD + */ +bool mvhd_file_is_vhd(FILE* f); + +/** + * \brief Open a VHD image for reading and/or writing + * + * The returned pointer contains all required values and structures (and files) to + * read and write to a VHD file. + * + * Remember to call mvhd_close() when you are finished. + * + * \param [in] Absolute path to VHD file. Relative path will cause issues when opening + * a differencing VHD file + * \param [in] readonly set this to true to open the VHD in a read only manner + * \param [out] err will be set if the VHD fails to open. Value could be one of + * MVHD_ERR_MEM, MVHD_ERR_FILE, MVHD_ERR_NOT_VHD, MVHD_ERR_FOOTER_CHECKSUM, MVHD_ERR_SPARSE_CHECKSUM, + * MVHD_ERR_TYPE, MVHD_ERR_TIMESTAMP + * If MVHD_ERR_FILE is set, mvhd_errno will be set to the appropriate system errno value + * + * \return MVHDMeta pointer. If NULL, check err. err may also be set to MVHD_ERR_TIMESTAMP if + * opening a differencing VHD. + */ +MVHDMeta* mvhd_open(const char* path, bool readonly, int* err); + +/** + * \brief Update the parent modified timestamp in the VHD file + * + * Differencing VHD's use a parent last modified timestamp to try and detect if the + * parent has been modified after the child has been created. However, this is rather + * fragile and can be broken by moving/copying the parent. Also, MS DiskPart does not + * set this timestamp in the child :( + * + * Be careful when using this function that you don't update the timestamp after the + * parent actually has been modified. + * + * \param [in] vhdm Differencing VHD to update. + * \param [out] err will be set if the timestamp could not be updated + * + * \return non-zero on error, 0 on success + */ +int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err); + +/** + * \brief Create a fixed VHD image + * + * \param [in] path is the absolute path to the image to create + * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [out] err indicates what error occurred, if any + * \param [out] progress_callback optional; if not NULL, gets called to indicate progress on the creation operation + * + * \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback); + +/** + * \brief Create sparse (dynamic) VHD image. + * + * \param [in] path is the absolute path to the VHD file to create + * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err); + +/** + * \brief Create differencing VHD imagee. + * + * \param [in] path is the absolute path to the VHD file to create + * \param [in] par_path is the absolute path to a parent image. If NULL, a sparse image is created, otherwise create a differencing image + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err); + +/** + * \brief Create a VHD using the provided options + * + * Use mvhd_create_ex if you want more control over the VHD's options. For quick creation, you can use mvhd_create_fixed, mvhd_create_sparse, or mvhd_create_diff. + * + * \param [in] options the VHD creation options. + * \param [out] err indicates what error occurred, if any + * + * \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err); + +/** + * \brief Safely close a VHD image + * + * \param [in] vhdm MiniVHD data structure to close + */ +void mvhd_close(MVHDMeta* vhdm); + +/** + * \brief Calculate hard disk geometry from a provided size + * + * The VHD format uses Cylinder, Heads, Sectors per Track (CHS) when accessing the disk. + * The size of the disk can be determined from C * H * S * sector_size. + * + * Note, maximum geometry size (in bytes) is 65535 * 16 * 255 * 512, which is 127GB. + * However, the maximum VHD size is 2040GB. For VHDs larger than 127GB, the geometry size will be + * smaller than the actual VHD size. + * + * This function determines the appropriate CHS geometry from a provided size in bytes. + * The calculations used are those provided in "Appendix: CHS Calculation" from the document + * "Virtual Hard Disk Image Format Specification" provided by Microsoft. + * + * \param [in] size the desired VHD image size, in bytes + * + * \return MVHDGeom the calculated geometry. This can be used in the appropriate create functions. + */ +MVHDGeom mvhd_calculate_geometry(uint64_t size); + +/** + * \brief Convert a raw disk image to a fixed VHD image + * + * \param [in] utf8_raw_path is the path of the raw image to convert + * \param [in] utf8_vhd_path is the path of the VHD to create + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err); + +/** + * \brief Convert a raw disk image to a sparse VHD image + * + * \param [in] utf8_raw_path is the path of the raw image to convert + * \param [in] utf8_vhd_path is the path of the VHD to create + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err); + +/** + * \brief Convert a VHD image to a raw disk image + * + * \param [in] utf8_vhd_path is the path of the VHD to convert + * \param [in] utf8_raw_path is the path of the raw image to create + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns the raw disk image FILE pointer + */ +FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err); + +/** + * \brief Read sectors from VHD file + * + * Read num_sectors, beginning at offset from the VHD file into a buffer + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset the sector offset from which to start reading from + * \param [in] num_sectors the number of sectors to read + * \param [out] out_buff the buffer to write sector data to + * + * \return the number of sectors that were not read, or zero + */ +int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Write sectors to VHD file + * + * Write num_sectors, beginning at offset from a buffer VHD file into the VHD file + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset the sector offset from which to start writing to + * \param [in] num_sectors the number of sectors to write + * \param [in] in_buffer the buffer to write sector data to + * + * \return the number of sectors that were not written, or zero + */ +int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +/** + * \brief Write zeroed sectors to VHD file + * + * Write num_sectors, beginning at offset, of zero data into the VHD file. + * We reuse the existing write functions, with a preallocated zero buffer as + * our source buffer. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset the sector offset from which to start writing to + * \param [in] num_sectors the number of sectors to write + * + * \return the number of sectors that were not written, or zero + */ +int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors); +#endif \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_convert.c b/src/disk/minivhd/minivhd_convert.c new file mode 100644 index 000000000..231e0f9b8 --- /dev/null +++ b/src/disk/minivhd/minivhd_convert.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include "minivhd_create.h" +#include "minivhd_internal.h" +#include "minivhd_util.h" +#include "minivhd.h" + +static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err); + +static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err) { + FILE *raw_img = mvhd_fopen(utf8_raw_path, "rb", err); + if (raw_img == NULL) { + *err = MVHD_ERR_FILE; + return NULL; + } + if (geom == NULL) { + *err = MVHD_ERR_INVALID_GEOM; + return NULL; + } + mvhd_fseeko64(raw_img, 0, SEEK_END); + uint64_t size_bytes = (uint64_t)mvhd_ftello64(raw_img); + MVHDGeom new_geom = mvhd_calculate_geometry(size_bytes); + if (mvhd_calc_size_bytes(&new_geom) != size_bytes) { + *err = MVHD_ERR_CONV_SIZE; + return NULL; + } + geom->cyl = new_geom.cyl; + geom->heads = new_geom.heads; + geom->spt = new_geom.spt; + mvhd_fseeko64(raw_img, 0, SEEK_SET); + return raw_img; +} + +MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) { + MVHDGeom geom; + FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err); + if (raw_img == NULL) { + return NULL; + } + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + MVHDMeta *vhdm = mvhd_create_fixed_raw(utf8_vhd_path, raw_img, size_in_bytes, &geom, err, NULL); + if (vhdm == NULL) { + return NULL; + } + return vhdm; +} +MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) { + MVHDGeom geom; + MVHDMeta *vhdm = NULL; + FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err); + if (raw_img == NULL) { + return NULL; + } + vhdm = mvhd_create_sparse(utf8_vhd_path, geom, err); + if (vhdm == NULL) { + goto end; + } + uint8_t buff[4096] = {0}; // 8 sectors + uint8_t empty_buff[4096] = {0}; + int total_sectors = mvhd_calc_size_sectors(&geom); + int copy_sect = 0; + for (int i = 0; i < total_sectors; i += 8) { + copy_sect = 8; + if ((i + 8) >= total_sectors) { + copy_sect = total_sectors - i; + memset(buff, 0, sizeof buff); + } + fread(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img); + /* Only write data if there's data to write, to take advantage of the sparse VHD format */ + if (memcmp(buff, empty_buff, sizeof buff) != 0) { + mvhd_write_sectors(vhdm, i, copy_sect, buff); + } + } +end: + fclose(raw_img); + return vhdm; +} +FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err) { + FILE *raw_img = mvhd_fopen(utf8_raw_path, "wb", err); + if (raw_img == NULL) { + return NULL; + } + MVHDMeta *vhdm = mvhd_open(utf8_vhd_path, true, err); + if (vhdm == NULL) { + fclose(raw_img); + return NULL; + } + uint8_t buff[4096] = {0}; // 8 sectors + int total_sectors = mvhd_calc_size_sectors((MVHDGeom*)&vhdm->footer.geom); + int copy_sect = 0; + for (int i = 0; i < total_sectors; i += 8) { + copy_sect = 8; + if ((i + 8) >= total_sectors) { + copy_sect = total_sectors - i; + } + mvhd_read_sectors(vhdm, i, copy_sect, buff); + fwrite(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img); + } + mvhd_close(vhdm); + mvhd_fseeko64(raw_img, 0, SEEK_SET); + return raw_img; +} \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_create.c b/src/disk/minivhd/minivhd_create.c new file mode 100644 index 000000000..9e34ece9d --- /dev/null +++ b/src/disk/minivhd/minivhd_create.c @@ -0,0 +1,482 @@ +#include +#include +#include +#include +#include +#include "cwalk.h" +#include "libxml2_encoding.h" +#include "minivhd_internal.h" +#include "minivhd_util.h" +#include "minivhd_struct_rw.h" +#include "minivhd_io.h" +#include "minivhd_create.h" +#include "minivhd.h" + +static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off); +static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors); +static int mvhd_gen_par_loc(MVHDSparseHeader* header, + const char* child_path, + const char* par_path, + uint64_t start_offset, + mvhd_utf16* w2ku_path_buff, + mvhd_utf16* w2ru_path_buff, + MVHDError* err); +static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err); + +/** + * \brief Populate a VHD footer + * + * \param [in] footer to populate + * \param [in] size_in_bytes is the total size of the virtual hard disk in bytes + * \param [in] geom to use + * \param [in] type of HVD that is being created + * \param [in] sparse_header_off, an absolute file offset to the sparse header. Not used for fixed VHD images + */ +static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off) { + memcpy(footer->cookie, "conectix", sizeof footer->cookie); + footer->features = 0x00000002; + footer->fi_fmt_vers = 0x00010000; + footer->data_offset = (type == MVHD_TYPE_DIFF || type == MVHD_TYPE_DYNAMIC) ? sparse_header_off : 0xffffffffffffffff; + footer->timestamp = vhd_calc_timestamp(); + memcpy(footer->cr_app, "mvhd", sizeof footer->cr_app); + footer->cr_vers = 0x000e0000; + memcpy(footer->cr_host_os, "Wi2k", sizeof footer->cr_host_os); + footer->orig_sz = footer->curr_sz = size_in_bytes; + footer->geom.cyl = geom->cyl; + footer->geom.heads = geom->heads; + footer->geom.spt = geom->spt; + footer->disk_type = type; + mvhd_generate_uuid(footer->uuid); + footer->checksum = mvhd_gen_footer_checksum(footer); +} + +/** + * \brief Populate a VHD sparse header + * + * \param [in] header for sparse and differencing images + * \param [in] num_blks is the number of data blocks that the image contains + * \param [in] bat_offset is the absolute file offset for start of the Block Allocation Table + * \param [in] block_size_in_sectors is the block size in sectors. + */ +static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors) { + memcpy(header->cookie, "cxsparse", sizeof header->cookie); + header->data_offset = 0xffffffffffffffff; + header->bat_offset = bat_offset; + header->head_vers = 0x00010000; + header->max_bat_ent = num_blks; + header->block_sz = block_size_in_sectors * (uint32_t)MVHD_SECTOR_SIZE; + header->checksum = mvhd_gen_sparse_checksum(header); +} + +/** + * \brief Generate parent locators for differencing VHD images + * + * \param [in] header the sparse header to populate with parent locator entries + * \param [in] child_path is the full path to the VHD being created + * \param [in] par_path is the full path to the parent image + * \param [in] start_offset is the absolute file offset from where to start storing the entries themselves. Must be sector aligned. + * \param [out] w2ku_path_buff is a buffer containing the full path to the parent, encoded as UTF16-LE + * \param [out] w2ru_path_buff is a buffer containing the relative path to the parent, encoded as UTF16-LE + * \param [out] err indicates what error occurred, if any + * + * \retval 0 if success + * \retval < 0 if an error occurrs. Check value of *err for actual error + */ +static int mvhd_gen_par_loc(MVHDSparseHeader* header, + const char* child_path, + const char* par_path, + uint64_t start_offset, + mvhd_utf16* w2ku_path_buff, + mvhd_utf16* w2ru_path_buff, + MVHDError* err) { + /* Get our paths to store in the differencing VHD. We want both the absolute path to the parent, + as well as the relative path from the child VHD */ + int rv = 0; + char* par_filename; + size_t par_fn_len; + char rel_path[MVHD_MAX_PATH_BYTES] = {0}; + char child_dir[MVHD_MAX_PATH_BYTES] = {0}; + size_t child_dir_len; + if (strlen(child_path) < sizeof child_dir) { + strcpy(child_dir, child_path); + } else { + *err = MVHD_ERR_PATH_LEN; + rv = -1; + goto end; + } + cwk_path_get_basename(par_path, (const char**)&par_filename, &par_fn_len); + cwk_path_get_dirname(child_dir, &child_dir_len); + child_dir[child_dir_len] = '\0'; + size_t rel_len = cwk_path_get_relative(child_dir, par_path, rel_path, sizeof rel_path); + if (rel_len > sizeof rel_path) { + *err = MVHD_ERR_PATH_LEN; + rv = -1; + goto end; + } + /* We have our paths, now store the parent filename directly in the sparse header. */ + int outlen = sizeof header->par_utf16_name; + int utf_ret; + utf_ret = UTF8ToUTF16BE((unsigned char*)header->par_utf16_name, &outlen, (const unsigned char*)par_filename, (int*)&par_fn_len); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, (int*)err); + rv = -1; + goto end; + } + + /* And encode the paths to UTF16-LE */ + size_t par_path_len = strlen(par_path); + outlen = sizeof *w2ku_path_buff * MVHD_MAX_PATH_CHARS; + utf_ret = UTF8ToUTF16LE((unsigned char*)w2ku_path_buff, &outlen, (const unsigned char*)par_path, (int*)&par_path_len); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, (int*)err); + rv = -1; + goto end; + } + int w2ku_len = utf_ret; + outlen = sizeof *w2ru_path_buff * MVHD_MAX_PATH_CHARS; + utf_ret = UTF8ToUTF16LE((unsigned char*)w2ru_path_buff, &outlen, (const unsigned char*)rel_path, (int*)&rel_len); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, (int*)err); + rv = -1; + goto end; + } + int w2ru_len = utf_ret; + /** + * Finally populate the parent locaters in the sparse header. + * This is the information needed to find the paths saved elsewhere + * in the VHD image + */ + + /* Note about the plat_data_space field: The VHD spec says this field stores the number of sectors needed to store the locator path. + * However, Hyper-V and VPC store the number of bytes, not the number of sectors, and will refuse to open VHDs which have the + * number of sectors in this field. + * See https://stackoverflow.com/questions/40760181/mistake-in-virtual-hard-disk-image-format-specification + */ + header->par_loc_entry[0].plat_code = MVHD_DIF_LOC_W2KU; + header->par_loc_entry[0].plat_data_len = (uint32_t)w2ku_len; + header->par_loc_entry[0].plat_data_offset = (uint64_t)start_offset; + header->par_loc_entry[0].plat_data_space = ((header->par_loc_entry[0].plat_data_len / MVHD_SECTOR_SIZE) + 1) * MVHD_SECTOR_SIZE; + header->par_loc_entry[1].plat_code = MVHD_DIF_LOC_W2RU; + header->par_loc_entry[1].plat_data_len = (uint32_t)w2ru_len; + header->par_loc_entry[1].plat_data_offset = (uint64_t)start_offset + ((uint64_t)header->par_loc_entry[0].plat_data_space); + header->par_loc_entry[1].plat_data_space = ((header->par_loc_entry[1].plat_data_len / MVHD_SECTOR_SIZE) + 1) * MVHD_SECTOR_SIZE; + goto end; + +end: + return rv; +} + +MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback) { + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + return mvhd_create_fixed_raw(path, NULL, size_in_bytes, &geom, err, progress_callback); +} + +/** + * \brief internal function that implements public mvhd_create_fixed() functionality + * + * Contains one more parameter than the public function, to allow using an existing + * raw disk image as the data source for the new fixed VHD. + * + * \param [in] raw_image file handle to a raw disk image to populate VHD + */ +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback) { + uint8_t img_data[MVHD_SECTOR_SIZE] = {0}; + uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; + MVHDMeta* vhdm = calloc(1, sizeof *vhdm); + if (vhdm == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) { + *err = MVHD_ERR_INVALID_GEOM; + goto cleanup_vhdm; + } + FILE* f = mvhd_fopen(path, "wb+", err); + if (f == NULL) { + goto cleanup_vhdm; + } + mvhd_fseeko64(f, 0, SEEK_SET); + uint32_t size_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE); + uint32_t s; + if (progress_callback) + progress_callback(0, size_sectors); + if (raw_img != NULL) { + mvhd_fseeko64(raw_img, 0, SEEK_END); + uint64_t raw_size = (uint64_t)mvhd_ftello64(raw_img); + MVHDGeom raw_geom = mvhd_calculate_geometry(raw_size); + if (mvhd_calc_size_bytes(&raw_geom) != raw_size) { + *err = MVHD_ERR_CONV_SIZE; + goto cleanup_vhdm; + } + mvhd_gen_footer(&vhdm->footer, raw_size, geom, MVHD_TYPE_FIXED, 0); + mvhd_fseeko64(raw_img, 0, SEEK_SET); + for (s = 0; s < size_sectors; s++) { + fread(img_data, sizeof img_data, 1, raw_img); + fwrite(img_data, sizeof img_data, 1, f); + if (progress_callback) + progress_callback(s + 1, size_sectors); + } + } else { + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_FIXED, 0); + for (s = 0; s < size_sectors; s++) { + fwrite(img_data, sizeof img_data, 1, f); + if (progress_callback) + progress_callback(s + 1, size_sectors); + } + } + mvhd_footer_to_buffer(&vhdm->footer, footer_buff); + fwrite(footer_buff, sizeof footer_buff, 1, f); + fclose(f); + f = NULL; + free(vhdm); + vhdm = mvhd_open(path, false, err); + goto end; + +cleanup_vhdm: + free(vhdm); + vhdm = NULL; +end: + return vhdm; +} + +/** + * \brief Create sparse or differencing VHD image. + * + * \param [in] path is the absolute path to the VHD file to create + * \param [in] par_path is the absolute path to a parent image. If NULL, a sparse image is created, otherwise create a differencing image + * \param [in] size_in_bytes is the total size in bytes of the virtual hard disk image + * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [in] block_size_in_sectors is the block size in sectors + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err) { + uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; + uint8_t sparse_buff[MVHD_SPARSE_SIZE] = {0}; + uint8_t bat_sect[MVHD_SECTOR_SIZE]; + MVHDGeom par_geom = {0}; + memset(bat_sect, 0xffffffff, sizeof bat_sect); + MVHDMeta* vhdm = NULL; + MVHDMeta* par_vhdm = NULL; + mvhd_utf16* w2ku_path_buff = NULL; + mvhd_utf16* w2ru_path_buff = NULL; + uint32_t par_mod_timestamp = 0; + if (par_path != NULL) { + par_mod_timestamp = mvhd_file_mod_timestamp(par_path, err); + if (*err != 0) { + goto end; + } + par_vhdm = mvhd_open(par_path, true, err); + if (par_vhdm == NULL) { + goto end; + } + } + vhdm = calloc(1, sizeof *vhdm); + if (vhdm == NULL) { + *err = MVHD_ERR_MEM; + goto cleanup_par_vhdm; + } + if (par_vhdm != NULL) { + /* We use the geometry from the parent VHD, not what was passed in */ + par_geom.cyl = par_vhdm->footer.geom.cyl; + par_geom.heads = par_vhdm->footer.geom.heads; + par_geom.spt = par_vhdm->footer.geom.spt; + geom = &par_geom; + size_in_bytes = par_vhdm->footer.curr_sz; + } else if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) { + *err = MVHD_ERR_INVALID_GEOM; + goto cleanup_vhdm; + } + + FILE* f = mvhd_fopen(path, "wb+", err); + if (f == NULL) { + goto cleanup_vhdm; + } + mvhd_fseeko64(f, 0, SEEK_SET); + /* Note, the sparse header follows the footer copy at the beginning of the file */ + if (par_path == NULL) { + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DYNAMIC, MVHD_FOOTER_SIZE); + } else { + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DIFF, MVHD_FOOTER_SIZE); + } + mvhd_footer_to_buffer(&vhdm->footer, footer_buff); + /* As mentioned, start with a copy of the footer */ + fwrite(footer_buff, sizeof footer_buff, 1, f); + /** + * Calculate the number of (2MB or 512KB) data blocks required to store the entire + * contents of the disk image, followed by the number of sectors the + * BAT occupies in the image. Note, the BAT is sector aligned, and is padded + * to the next sector boundary + * */ + uint32_t size_in_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE); + uint32_t num_blks = size_in_sectors / block_size_in_sectors; + if (size_in_sectors % block_size_in_sectors != 0) { + num_blks += 1; + } + uint32_t num_bat_sect = num_blks / MVHD_BAT_ENT_PER_SECT; + if (num_blks % MVHD_BAT_ENT_PER_SECT != 0) { + num_bat_sect += 1; + } + /* Storing the BAT directly following the footer and header */ + uint64_t bat_offset = MVHD_FOOTER_SIZE + MVHD_SPARSE_SIZE; + uint64_t par_loc_offset = 0; + + /** + * If creating a differencing VHD, populate the sparse header with additional + * data about the parent image, and where to find it, and it's last modified timestamp + * */ + if (par_vhdm != NULL) { + /** + * Create output buffers to encode paths into. + * The paths are not stored directly in the sparse header, hence the need to + * store them in buffers to be written to the VHD image later + */ + w2ku_path_buff = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ku_path_buff); + if (w2ku_path_buff == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + w2ru_path_buff = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ru_path_buff); + if (w2ru_path_buff == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + memcpy(vhdm->sparse.par_uuid, par_vhdm->footer.uuid, sizeof vhdm->sparse.par_uuid); + par_loc_offset = bat_offset + ((uint64_t)num_bat_sect * MVHD_SECTOR_SIZE) + (5 * MVHD_SECTOR_SIZE); + if (mvhd_gen_par_loc(&vhdm->sparse, path, par_path, par_loc_offset, w2ku_path_buff, w2ru_path_buff, (MVHDError*)err) < 0) { + goto cleanup_vhdm; + } + vhdm->sparse.par_timestamp = par_mod_timestamp; + } + mvhd_gen_sparse_header(&vhdm->sparse, num_blks, bat_offset, block_size_in_sectors); + mvhd_header_to_buffer(&vhdm->sparse, sparse_buff); + fwrite(sparse_buff, sizeof sparse_buff, 1, f); + /* The BAT sectors need to be filled with 0xffffffff */ + for (uint32_t i = 0; i < num_bat_sect; i++) { + fwrite(bat_sect, sizeof bat_sect, 1, f); + } + mvhd_write_empty_sectors(f, 5); + /** + * If creating a differencing VHD, the paths to the parent image need to be written + * tp the file. Both absolute and relative paths are written + * */ + if (par_vhdm != NULL) { + uint64_t curr_pos = (uint64_t)mvhd_ftello64(f); + /* Double check my sums... */ + assert(curr_pos == par_loc_offset); + /* Fill the space required for location data with zero */ + uint8_t empty_sect[MVHD_SECTOR_SIZE] = {0}; + for (int i = 0; i < 2; i++) { + for (uint32_t j = 0; j < (vhdm->sparse.par_loc_entry[i].plat_data_space / MVHD_SECTOR_SIZE); j++) { + fwrite(empty_sect, sizeof empty_sect, 1, f); + } + } + /* Now write the location entries */ + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[0].plat_data_offset, SEEK_SET); + fwrite(w2ku_path_buff, vhdm->sparse.par_loc_entry[0].plat_data_len, 1, f); + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset, SEEK_SET); + fwrite(w2ru_path_buff, vhdm->sparse.par_loc_entry[1].plat_data_len, 1, f); + /* and reset the file position to continue */ + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset + vhdm->sparse.par_loc_entry[1].plat_data_space, SEEK_SET); + mvhd_write_empty_sectors(f, 5); + } + /* And finish with the footer */ + fwrite(footer_buff, sizeof footer_buff, 1, f); + fclose(f); + f = NULL; + free(vhdm); + vhdm = mvhd_open(path, false, err); + goto end; + +cleanup_vhdm: + free(vhdm); + vhdm = NULL; +cleanup_par_vhdm: + if (par_vhdm != NULL) { + mvhd_close(par_vhdm); + } +end: + free(w2ku_path_buff); + free(w2ru_path_buff); + return vhdm; +} + +MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err) { + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + return mvhd_create_sparse_diff(path, NULL, size_in_bytes, &geom, MVHD_BLOCK_LARGE, err); +} + +MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err) { + return mvhd_create_sparse_diff(path, par_path, 0, NULL, MVHD_BLOCK_LARGE, err); +} + +MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err) { + uint32_t geom_sector_size; + switch (options.type) + { + case MVHD_TYPE_FIXED: + case MVHD_TYPE_DYNAMIC: + geom_sector_size = mvhd_calc_size_sectors(&(options.geometry)); + if ((options.size_in_bytes > 0 && (options.size_in_bytes % MVHD_SECTOR_SIZE) > 0) + || (options.size_in_bytes > MVHD_MAX_SIZE_IN_BYTES) + || (options.size_in_bytes == 0 && geom_sector_size == 0)) + { + *err = MVHD_ERR_INVALID_SIZE; + return NULL; + } + + if (options.size_in_bytes > 0 && ((uint64_t)geom_sector_size * MVHD_SECTOR_SIZE) > options.size_in_bytes) + { + *err = MVHD_ERR_INVALID_GEOM; + return NULL; + } + + if (options.size_in_bytes == 0) + options.size_in_bytes = (uint64_t)geom_sector_size * MVHD_SECTOR_SIZE; + + if (geom_sector_size == 0) + options.geometry = mvhd_calculate_geometry(options.size_in_bytes); + break; + case MVHD_TYPE_DIFF: + if (options.parent_path == NULL) + { + *err = MVHD_ERR_FILE; + return NULL; + } + break; + default: + *err = MVHD_ERR_TYPE; + return NULL; + } + + if (options.path == NULL) + { + *err = MVHD_ERR_FILE; + return NULL; + } + + if (options.type != MVHD_TYPE_FIXED) + { + if (options.block_size_in_sectors == MVHD_BLOCK_DEFAULT) + options.block_size_in_sectors = MVHD_BLOCK_LARGE; + + if (options.block_size_in_sectors != MVHD_BLOCK_LARGE && options.block_size_in_sectors != MVHD_BLOCK_SMALL) + { + *err = MVHD_ERR_INVALID_BLOCK_SIZE; + return NULL; + } + } + + switch (options.type) + { + case MVHD_TYPE_FIXED: + return mvhd_create_fixed_raw(options.path, NULL, options.size_in_bytes, &(options.geometry), err, options.progress_callback); + case MVHD_TYPE_DYNAMIC: + return mvhd_create_sparse_diff(options.path, NULL, options.size_in_bytes, &(options.geometry), options.block_size_in_sectors, err); + case MVHD_TYPE_DIFF: + return mvhd_create_sparse_diff(options.path, options.parent_path, 0, NULL, options.block_size_in_sectors, err); + } + + return NULL; /* Make the compiler happy */ +} \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_create.h b/src/disk/minivhd/minivhd_create.h new file mode 100644 index 000000000..9840d19ff --- /dev/null +++ b/src/disk/minivhd/minivhd_create.h @@ -0,0 +1,8 @@ +#ifndef MINIVHD_CREATE_H +#define MINIVHD_CREATE_H +#include +#include "minivhd.h" + +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback); + +#endif \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_internal.h b/src/disk/minivhd/minivhd_internal.h new file mode 100644 index 000000000..ea75284f8 --- /dev/null +++ b/src/disk/minivhd/minivhd_internal.h @@ -0,0 +1,96 @@ +#ifndef MINIVHD_INTERNAL_H +#define MINIVHD_INTERNAL_H +#include +#include +#include + +#define MVHD_FOOTER_SIZE 512 +#define MVHD_SPARSE_SIZE 1024 + +#define MVHD_SECTOR_SIZE 512 +#define MVHD_BAT_ENT_PER_SECT 128 + +#define MVHD_MAX_SIZE_IN_BYTES 0x1fe00000000 + +#define MVHD_SPARSE_BLK 0xffffffff +/* For simplicity, we don't handle paths longer than this + * Note, this is the max path in characters, as that is what + * Windows uses + */ +#define MVHD_MAX_PATH_CHARS 260 +#define MVHD_MAX_PATH_BYTES 1040 + +#define MVHD_DIF_LOC_W2RU 0x57327275 +#define MVHD_DIF_LOC_W2KU 0x57326B75 + +typedef struct MVHDSectorBitmap { + uint8_t* curr_bitmap; + int sector_count; + int curr_block; +} MVHDSectorBitmap; + +typedef struct MVHDFooter { + uint8_t cookie[8]; + uint32_t features; + uint32_t fi_fmt_vers; + uint64_t data_offset; + uint32_t timestamp; + uint8_t cr_app[4]; + uint32_t cr_vers; + uint8_t cr_host_os[4]; + uint64_t orig_sz; + uint64_t curr_sz; + struct { + uint16_t cyl; + uint8_t heads; + uint8_t spt; + } geom; + uint32_t disk_type; + uint32_t checksum; + uint8_t uuid[16]; + uint8_t saved_st; + uint8_t reserved[427]; +} MVHDFooter; + +typedef struct MVHDSparseHeader { + uint8_t cookie[8]; + uint64_t data_offset; + uint64_t bat_offset; + uint32_t head_vers; + uint32_t max_bat_ent; + uint32_t block_sz; + uint32_t checksum; + uint8_t par_uuid[16]; + uint32_t par_timestamp; + uint32_t reserved_1; + uint8_t par_utf16_name[512]; + struct { + uint32_t plat_code; + uint32_t plat_data_space; + uint32_t plat_data_len; + uint32_t reserved; + uint64_t plat_data_offset; + } par_loc_entry[8]; + uint8_t reserved_2[256]; +} MVHDSparseHeader; + +typedef struct MVHDMeta MVHDMeta; +struct MVHDMeta { + FILE* f; + bool readonly; + char filename[MVHD_MAX_PATH_BYTES]; + struct MVHDMeta* parent; + MVHDFooter footer; + MVHDSparseHeader sparse; + uint32_t* block_offset; + int sect_per_block; + MVHDSectorBitmap bitmap; + int (*read_sectors)(MVHDMeta*, uint32_t, int, void*); + int (*write_sectors)(MVHDMeta*, uint32_t, int, void*); + struct { + uint8_t* zero_data; + int sector_count; + } format_buffer; +}; + +#endif \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_io.c b/src/disk/minivhd/minivhd_io.c new file mode 100644 index 000000000..8e9172e63 --- /dev/null +++ b/src/disk/minivhd/minivhd_io.c @@ -0,0 +1,276 @@ +/** + * \file + * \brief Sector reading and writing implementations + */ + +#include +#include +#include "minivhd_internal.h" +#include "minivhd_util.h" + +/* The following bit array macros adapted from + http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html */ + +#define VHD_SETBIT(A,k) ( A[(k/8)] |= (0x80 >> (k%8)) ) +#define VHD_CLEARBIT(A,k) ( A[(k/8)] &= ~(0x80 >> (k%8)) ) +#define VHD_TESTBIT(A,k) ( A[(k/8)] & (0x80 >> (k%8)) ) + +static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect); +static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk); +static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk); +static void mvhd_create_block(MVHDMeta* vhdm, int blk); +static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm); + +/** + * \brief Check that we will not be overflowing buffers + * + * \param [in] offset The offset from which we are beginning from + * \param [in] num_sectors The number of sectors which we desire to read/write + * \param [in] total_sectors The total number of sectors available + * \param [out] transfer_sect The number of sectors to actually write. + * This may be lower than num_sectors if offset + num_sectors >= total_sectors + * \param [out] trunc_sectors The number of sectors truncated if transfer_sectors < num_sectors + */ +static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect) { + *transfer_sect = num_sectors; + *trunc_sect = 0; + if ((total_sectors - offset) < (uint32_t)*transfer_sect) { + *transfer_sect = total_sectors - offset; + *trunc_sect = num_sectors - *transfer_sect; + } +} + +void mvhd_write_empty_sectors(FILE* f, int sector_count) { + uint8_t zero_bytes[MVHD_SECTOR_SIZE] = {0}; + for (int i = 0; i < sector_count; i++) { + fwrite(zero_bytes, sizeof zero_bytes, 1, f); + } +} + +/** + * \brief Read the sector bitmap for a block. + * + * If the block is sparse, the sector bitmap in memory will be + * zeroed. Otherwise, the sector bitmap is read from the VHD file. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] blk The block for which to read the sector bitmap from + */ +static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk) { + if (vhdm->block_offset[blk] != MVHD_SPARSE_BLK) { + mvhd_fseeko64(vhdm->f, (uint64_t)vhdm->block_offset[blk] * MVHD_SECTOR_SIZE, SEEK_SET); + fread(vhdm->bitmap.curr_bitmap, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE, 1, vhdm->f); + } else { + memset(vhdm->bitmap.curr_bitmap, 0, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE); + } + vhdm->bitmap.curr_block = blk; +} + +/** + * \brief Write the current sector bitmap in memory to file + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm) { + if (vhdm->bitmap.curr_block >= 0) { + int64_t abs_offset = (int64_t)vhdm->block_offset[vhdm->bitmap.curr_block] * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, abs_offset, SEEK_SET); + fwrite(vhdm->bitmap.curr_bitmap, MVHD_SECTOR_SIZE, vhdm->bitmap.sector_count, vhdm->f); + } +} + +/** + * \brief Write block offset from memory into file + * + * \param [in] vhdm MiniVHD data structure + * \param [in] blk The block for which to write the offset for + */ +static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk) { + uint64_t table_offset = vhdm->sparse.bat_offset + ((uint64_t)blk * sizeof *vhdm->block_offset); + uint32_t offset = mvhd_to_be32(vhdm->block_offset[blk]); + mvhd_fseeko64(vhdm->f, table_offset, SEEK_SET); + fwrite(&offset, sizeof offset, 1, vhdm->f); +} + +/** + * \brief Create an empty block in a sparse or differencing VHD image + * + * VHD images store data in blocks, which are typically 4096 sectors in size + * (~2MB). These blocks may be stored on disk in any order. Blocks are created + * on demand when required. + * + * This function creates new, empty blocks, by replacing the footer at the end of the file + * and then re-inserting the footer at the new file end. The BAT table entry for the + * new block is updated with the new offset. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] blk The block number to create + */ +static void mvhd_create_block(MVHDMeta* vhdm, int blk) { + uint8_t footer[MVHD_FOOTER_SIZE]; + /* Seek to where the footer SHOULD be */ + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + fread(footer, sizeof footer, 1, vhdm->f); + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + if (!mvhd_is_conectix_str(footer)) { + /* Oh dear. We use the header instead, since something has gone wrong at the footer */ + mvhd_fseeko64(vhdm->f, 0, SEEK_SET); + fread(footer, sizeof footer, 1, vhdm->f); + mvhd_fseeko64(vhdm->f, 0, SEEK_END); + } + int64_t abs_offset = mvhd_ftello64(vhdm->f); + if (abs_offset % MVHD_SECTOR_SIZE != 0) { + /* Yikes! We're supposed to be on a sector boundary. Add some padding */ + int64_t padding_amount = (int64_t)MVHD_SECTOR_SIZE - (abs_offset % MVHD_SECTOR_SIZE); + uint8_t zero_byte = 0; + for (int i = 0; i < padding_amount; i++) { + fwrite(&zero_byte, sizeof zero_byte, 1, vhdm->f); + } + abs_offset += padding_amount; + } + uint32_t sect_offset = (uint32_t)(abs_offset / MVHD_SECTOR_SIZE); + int blk_size_sectors = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE; + mvhd_write_empty_sectors(vhdm->f, vhdm->bitmap.sector_count + blk_size_sectors); + /* Add a bit of padding. That's what Windows appears to do, although it's not strictly necessary... */ + mvhd_write_empty_sectors(vhdm->f, 5); + /* And we finish with the footer */ + fwrite(footer, sizeof footer, 1, vhdm->f); + /* We no longer have a sparse block. Update that BAT! */ + vhdm->block_offset[blk] = sect_offset; + mvhd_write_bat_entry(vhdm, blk); +} + +int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + int64_t addr; + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + addr = (int64_t)offset * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + fread(out_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f); + return truncated_sectors; +} + +int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + uint8_t* buff = (uint8_t*)out_buff; + int64_t addr; + uint32_t s, ls; + int blk, prev_blk, sib; + ls = offset + transfer_sectors; + prev_blk = -1; + for (s = offset; s < ls; s++) { + blk = s / vhdm->sect_per_block; + sib = s % vhdm->sect_per_block; + if (blk != prev_blk) { + prev_blk = blk; + if (vhdm->bitmap.curr_block != blk) { + mvhd_read_sect_bitmap(vhdm, blk); + mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR); + } else { + addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + } + } + if (VHD_TESTBIT(vhdm->bitmap.curr_bitmap, sib)) { + fread(buff, MVHD_SECTOR_SIZE, 1, vhdm->f); + } else { + memset(buff, 0, MVHD_SECTOR_SIZE); + mvhd_fseeko64(vhdm->f, MVHD_SECTOR_SIZE, SEEK_CUR); + } + buff += MVHD_SECTOR_SIZE; + } + return truncated_sectors; +} + +int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + uint8_t* buff = (uint8_t*)out_buff; + MVHDMeta* curr_vhdm = vhdm; + uint32_t s, ls; + int blk, sib; + ls = offset + transfer_sectors; + for (s = offset; s < ls; s++) { + while (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF) { + blk = s / curr_vhdm->sect_per_block; + sib = s % curr_vhdm->sect_per_block; + if (curr_vhdm->bitmap.curr_block != blk) { + mvhd_read_sect_bitmap(curr_vhdm, blk); + } + if (!VHD_TESTBIT(curr_vhdm->bitmap.curr_bitmap, sib)) { + curr_vhdm = curr_vhdm->parent; + } else { break; } + } + /* We handle actual sector reading using the fixed or sparse functions, + as a differencing VHD is also a sparse VHD */ + if (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF || curr_vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) { + mvhd_sparse_read(curr_vhdm, s, 1, buff); + } else { + mvhd_fixed_read(curr_vhdm, s, 1, buff); + } + curr_vhdm = vhdm; + buff += MVHD_SECTOR_SIZE; + } + return truncated_sectors; +} + +int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + int64_t addr; + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + addr = (int64_t)offset * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + fwrite(in_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f); + return truncated_sectors; +} + +int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + uint8_t* buff = (uint8_t*)in_buff; + int64_t addr; + uint32_t s, ls; + int blk, prev_blk, sib; + ls = offset + transfer_sectors; + prev_blk = -1; + for (s = offset; s < ls; s++) { + blk = s / vhdm->sect_per_block; + sib = s % vhdm->sect_per_block; + if (vhdm->block_offset[blk] == MVHD_SPARSE_BLK) { + /* "read" the sector bitmap first, before creating a new block, as the bitmap will be + zero either way */ + mvhd_read_sect_bitmap(vhdm, blk); + mvhd_create_block(vhdm, blk); + } + if (blk != prev_blk) { + if (vhdm->bitmap.curr_block != blk) { + if (prev_blk >= 0) { + /* Write the sector bitmap for the previous block, before we replace it. */ + mvhd_write_curr_sect_bitmap(vhdm); + } + mvhd_read_sect_bitmap(vhdm, blk); + mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR); + } else { + addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + } + prev_blk = blk; + } + fwrite(buff, MVHD_SECTOR_SIZE, 1, vhdm->f); + VHD_SETBIT(vhdm->bitmap.curr_bitmap, sib); + buff += MVHD_SECTOR_SIZE; + } + /* And write the sector bitmap for the last block we visited to disk */ + mvhd_write_curr_sect_bitmap(vhdm); + return truncated_sectors; +} + +int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + return 0; +} \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_io.h b/src/disk/minivhd/minivhd_io.h new file mode 100644 index 000000000..cdbfa6d77 --- /dev/null +++ b/src/disk/minivhd/minivhd_io.h @@ -0,0 +1,132 @@ +#ifndef MINIVHD_IO_H +#define MINIVHD_IO_H +#include "minivhd.h" + +/** + * \brief Write zero filled sectors to file. + * + * Note, the caller should set the file position before calling this + * function for correct operation. + * + * \param [in] f File to write sectors to + * \param [in] sector_count The number of sectors to write + */ +void mvhd_write_empty_sectors(FILE* f, int sector_count); + +/** + * \brief Read a fixed VHD image + * + * Fixed VHD images are essentially raw image files with a footer tacked on + * the end. They are therefore straightforward to write + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to read from + * \param [in] num_sectors The desired number of sectors to read + * \param [out] out_buff An output buffer to store read sectors. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were read from file + * \retval >0 < num_sectors were read from file + */ +int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Read a sparse VHD image + * + * Sparse, or dynamic images are VHD images that grow as data is written to them. + * + * This function implements the logic to read sectors from the file, taking into + * account the fact that blocks may be stored on disk in any order, and that the + * read could cross block boundaries. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to read from + * \param [in] num_sectors The desired number of sectors to read + * \param [out] out_buff An output buffer to store read sectors. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were read from file + * \retval >0 < num_sectors were read from file + */ +int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Read a differencing VHD image + * + * Differencing images are a variant of a sparse image. They contain the grow-on-demand + * properties of sparse images, but also reference a parent image. Data is read from the + * child image only if it is newer than the data stored in the parent image. + * + * This function implements the logic to read sectors from the child, or a parent image. + * Differencing images may have a differencing image as a parent, creating a chain of images. + * There is no theoretical chain length limit, although I do not consider long chains to be + * advisable. Verifying the parent-child relationship is not very robust. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to read from + * \param [in] num_sectors The desired number of sectors to read + * \param [out] out_buff An output buffer to store read sectors. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were read from file + * \retval >0 < num_sectors were read from file + */ +int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Write to a fixed VHD image + * + * Fixed VHD images are essentially raw image files with a footer tacked on + * the end. They are therefore straightforward to write + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to write to + * \param [in] num_sectors The desired number of sectors to write + * \param [in] in_buff A source buffer to write sectors from. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were written to file + * \retval >0 < num_sectors were written to file + */ +int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +/** + * \brief Write to a sparse or differencing VHD image + * + * Sparse, or dynamic images are VHD images that grow as data is written to them. + * + * Differencing images are a variant of a sparse image. They contain the grow-on-demand + * properties of sparse images, but also reference a parent image. Data is always written + * to the child image. This makes writing to differencing images essentially identical to + * writing to sparse images, hence they use the same function. + * + * This function implements the logic to write sectors to the file, taking into + * account the fact that blocks may be stored on disk in any order, and that the + * write operation could cross block boundaries. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to write to + * \param [in] num_sectors The desired number of sectors to write + * \param [in] in_buff A source buffer to write sectors from. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were written to file + * \retval >0 < num_sectors were written to file + */ +int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +/** + * \brief A no-op function to "write" to read-only VHD images + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to write to + * \param [in] num_sectors The desired number of sectors to write + * \param [in] in_buff A source buffer to write sectors from. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were written to file + * \retval >0 < num_sectors were written to file + */ +int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +#endif \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_manage.c b/src/disk/minivhd/minivhd_manage.c new file mode 100644 index 000000000..75e095332 --- /dev/null +++ b/src/disk/minivhd/minivhd_manage.c @@ -0,0 +1,533 @@ +/** + * \file + * \brief VHD management functions (open, close, read write etc) + */ + +#include +#include +#include +#include +#include +#include "cwalk.h" +#include "libxml2_encoding.h" +#include "minivhd_internal.h" +#include "minivhd_io.h" +#include "minivhd_util.h" +#include "minivhd_struct_rw.h" +#include "minivhd.h" + +int mvhd_errno = 0; +static char tmp_open_path[MVHD_MAX_PATH_BYTES] = {0}; +struct MVHDPaths { + char dir_path[MVHD_MAX_PATH_BYTES]; + char file_name[MVHD_MAX_PATH_BYTES]; + char w2ku_path[MVHD_MAX_PATH_BYTES]; + char w2ru_path[MVHD_MAX_PATH_BYTES]; + char joined_path[MVHD_MAX_PATH_BYTES]; + uint16_t tmp_src_path[MVHD_MAX_PATH_CHARS]; +}; + +static void mvhd_read_footer(MVHDMeta* vhdm); +static void mvhd_read_sparse_header(MVHDMeta* vhdm); +static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm); +static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm); +static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err); +static void mvhd_calc_sparse_values(MVHDMeta* vhdm); +static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err); + +/** + * \brief Populate data stuctures with content from a VHD footer + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_read_footer(MVHDMeta* vhdm) { + uint8_t buffer[MVHD_FOOTER_SIZE]; + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + fread(buffer, sizeof buffer, 1, vhdm->f); + mvhd_buffer_to_footer(&vhdm->footer, buffer); +} + +/** + * \brief Populate data stuctures with content from a VHD sparse header + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_read_sparse_header(MVHDMeta* vhdm) { + uint8_t buffer[MVHD_SPARSE_SIZE]; + mvhd_fseeko64(vhdm->f, vhdm->footer.data_offset, SEEK_SET); + fread(buffer, sizeof buffer, 1, vhdm->f); + mvhd_buffer_to_header(&vhdm->sparse, buffer); +} + +/** + * \brief Validate VHD footer checksum + * + * This works by generating a checksum from the footer, and comparing it against the stored checksum. + * + * \param [in] vhdm MiniVHD data structure + */ +static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm) { + return vhdm->footer.checksum == mvhd_gen_footer_checksum(&vhdm->footer); +} + +/** + * \brief Validate VHD sparse header checksum + * + * This works by generating a checksum from the sparse header, and comparing it against the stored checksum. + * + * \param [in] vhdm MiniVHD data structure + */ +static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm) { + return vhdm->sparse.checksum == mvhd_gen_sparse_checksum(&vhdm->sparse); +} + +/** + * \brief Read BAT into MiniVHD data structure + * + * The Block Allocation Table (BAT) is the structure in a sparse and differencing VHD which stores + * the 4-byte sector offsets for each data block. This function allocates enough memory to contain + * the entire BAT, and then reads the contents of the BAT into the buffer. + * + * \param [in] vhdm MiniVHD data structure + * \param [out] err this is populated with MVHD_ERR_MEM if the calloc fails + * + * \retval -1 if an error occurrs. Check value of err in this case + * \retval 0 if the function call succeeds + */ +static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err) { + vhdm->block_offset = calloc(vhdm->sparse.max_bat_ent, sizeof *vhdm->block_offset); + if (vhdm->block_offset == NULL) { + *err = MVHD_ERR_MEM; + return -1; + } + mvhd_fseeko64(vhdm->f, vhdm->sparse.bat_offset, SEEK_SET); + for (uint32_t i = 0; i < vhdm->sparse.max_bat_ent; i++) { + fread(&vhdm->block_offset[i], sizeof *vhdm->block_offset, 1, vhdm->f); + vhdm->block_offset[i] = mvhd_from_be32(vhdm->block_offset[i]); + } + return 0; +} + +/** + * \brief Perform a one-time calculation of some sparse VHD values + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_calc_sparse_values(MVHDMeta* vhdm) { + vhdm->sect_per_block = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE; + int bm_bytes = vhdm->sect_per_block / 8; + vhdm->bitmap.sector_count = bm_bytes / MVHD_SECTOR_SIZE; + if (bm_bytes % MVHD_SECTOR_SIZE > 0) { + vhdm->bitmap.sector_count++; + } +} + +/** + * \brief Allocate memory for a sector bitmap. + * + * Each data block is preceded by a sector bitmap. Each bit indicates whether the corresponding sector + * is considered 'clean' or 'dirty' (for sparse VHD images), or whether to read from the parent or current + * image (for differencing images). + * + * \param [in] vhdm MiniVHD data structure + * \param [out] err this is populated with MVHD_ERR_MEM if the calloc fails + * + * \retval -1 if an error occurrs. Check value of err in this case + * \retval 0 if the function call succeeds + */ +static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err) { + vhdm->bitmap.curr_bitmap = calloc(vhdm->bitmap.sector_count, MVHD_SECTOR_SIZE); + if (vhdm->bitmap.curr_bitmap == NULL) { + *err = MVHD_ERR_MEM; + return -1; + } + vhdm->bitmap.curr_block = -1; + return 0; +} + +/** + * \brief Check if the path for a given platform code exists + * + * From the available paths, both relative and absolute, construct a full path + * and attempt to open a file at that path. + * + * Note, this function makes no attempt to verify that the path is the correct + * VHD image, or even a VHD image at all. + * + * \param [in] paths a struct containing all available paths to work with + * \param [in] the platform code to try and obtain a path for. Setting this to zero + * will try using the directory of the child image + * + * \retval true if a file is found + * \retval false if a file is not found + */ +static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code) { + memset(paths->joined_path, 0, sizeof paths->joined_path); + FILE* f; + int cwk_ret, ferr; + enum cwk_path_style style = cwk_path_guess_style((const char*)paths->dir_path); + cwk_path_set_style(style); + cwk_ret = 1; + if (plat_code == MVHD_DIF_LOC_W2RU && *paths->w2ru_path) { + cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->w2ru_path, paths->joined_path, sizeof paths->joined_path); + } else if (plat_code == MVHD_DIF_LOC_W2KU && *paths->w2ku_path) { + memcpy(paths->joined_path, paths->w2ku_path, (sizeof paths->joined_path) - 1); + cwk_ret = 0; + } else if (plat_code == 0) { + cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->file_name, paths->joined_path, sizeof paths->joined_path); + } + if (cwk_ret > MVHD_MAX_PATH_BYTES) { + return false; + } + f = mvhd_fopen((const char*)paths->joined_path, "rb", &ferr); + if (f != NULL) { + /* We found a file at the requested path! */ + memcpy(tmp_open_path, paths->joined_path, (sizeof paths->joined_path) - 1); + tmp_open_path[sizeof tmp_open_path - 1] = '\0'; + fclose(f); + return true; + } else { + return false; + } +} + +/** + * \brief attempt to obtain a file path to a file that may be a valid VHD image + * + * Differential VHD images store both a UTF-16BE file name (or path), and up to + * eight "parent locator" entries. Using this information, this function tries to + * find a parent image. + * + * This function does not verify if the path returned is a valid parent image. + * + * \param [in] vhdm current MiniVHD data structure + * \param [out] err any errors that may occurr. Check this if NULL is returned + * + * \return a pointer to the global string `tmp_open_path`, or NULL if a path could + * not be found, or some error occurred + */ +static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) { + int utf_outlen, utf_inlen, utf_ret; + char* par_fp = NULL; + /* We can't resolve relative paths if we don't have an absolute + path to work with */ + if (!cwk_path_is_absolute((const char*)vhdm->filename)) { + *err = MVHD_ERR_PATH_REL; + goto end; + } + struct MVHDPaths* paths = calloc(1, sizeof *paths); + if (paths == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + size_t dirlen; + cwk_path_get_dirname((const char*)vhdm->filename, &dirlen); + if (dirlen >= sizeof paths->dir_path) { + *err = MVHD_ERR_PATH_LEN; + goto paths_cleanup; + } + memcpy(paths->dir_path, vhdm->filename, dirlen); + /* Get the filename field from the sparse header. */ + utf_outlen = (int)sizeof paths->file_name; + utf_inlen = (int)sizeof vhdm->sparse.par_utf16_name; + utf_ret = UTF16BEToUTF8((unsigned char*)paths->file_name, &utf_outlen, (const unsigned char*)vhdm->sparse.par_utf16_name, &utf_inlen); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, err); + goto paths_cleanup; + } + /* Now read the parent locator entries, both relative and absolute, if they exist */ + unsigned char* loc_path; + for (int i = 0; i < 8; i++) { + utf_outlen = MVHD_MAX_PATH_BYTES - 1; + if (vhdm->sparse.par_loc_entry[i].plat_code == MVHD_DIF_LOC_W2RU) { + loc_path = (unsigned char*)paths->w2ru_path; + } else if (vhdm->sparse.par_loc_entry[i].plat_code == MVHD_DIF_LOC_W2KU) { + loc_path = (unsigned char*)paths->w2ku_path; + } else { + continue; + } + utf_inlen = vhdm->sparse.par_loc_entry[i].plat_data_len; + if (utf_inlen > MVHD_MAX_PATH_BYTES) { + *err = MVHD_ERR_PATH_LEN; + goto paths_cleanup; + } + mvhd_fseeko64(vhdm->f, vhdm->sparse.par_loc_entry[i].plat_data_offset, SEEK_SET); + fread(paths->tmp_src_path, sizeof (uint8_t), utf_inlen, vhdm->f); + /* Note, the W2*u parent locators are UTF-16LE, unlike the filename field previously obtained, + which is UTF-16BE */ + utf_ret = UTF16LEToUTF8(loc_path, &utf_outlen, (const unsigned char*)paths->tmp_src_path, &utf_inlen); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, err); + goto paths_cleanup; + } + } + /* We have paths in UTF-8. We should have enough info to try and find the parent VHD */ + /* Does the relative path exist? */ + if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2RU)) { + par_fp = tmp_open_path; + goto paths_cleanup; + } + /* What about trying the child directory? */ + if (mvhd_parent_path_exists(paths, 0)) { + par_fp = tmp_open_path; + goto paths_cleanup; + } + /* Well, all else fails, try the stored absolute path, if it exists */ + if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2KU)) { + par_fp = tmp_open_path; + goto paths_cleanup; + } + /* If we reach this point, we could not find a path with a valid file */ + par_fp = NULL; + *err = MVHD_ERR_PAR_NOT_FOUND; + +paths_cleanup: + free(paths); + paths = NULL; +end: + return par_fp; +} + +/** + * \brief Attach the read/write function pointers to read/write functions + * + * Depending on the VHD type, different sector reading and writing functions are used. + * The functions are called via function pointers stored in the vhdm struct. + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_assign_io_funcs(MVHDMeta* vhdm) { + switch (vhdm->footer.disk_type) { + case MVHD_TYPE_FIXED: + vhdm->read_sectors = mvhd_fixed_read; + vhdm->write_sectors = mvhd_fixed_write; + break; + case MVHD_TYPE_DYNAMIC: + vhdm->read_sectors = mvhd_sparse_read; + vhdm->write_sectors = mvhd_sparse_diff_write; + break; + case MVHD_TYPE_DIFF: + vhdm->read_sectors = mvhd_diff_read; + vhdm->write_sectors = mvhd_sparse_diff_write; + break; + } + if (vhdm->readonly) { + vhdm->write_sectors = mvhd_noop_write; + } +} + +bool mvhd_file_is_vhd(FILE* f) { + if (f) { + uint8_t con_str[8]; + mvhd_fseeko64(f, -MVHD_FOOTER_SIZE, SEEK_END); + fread(con_str, sizeof con_str, 1, f); + return mvhd_is_conectix_str(con_str); + } else { + return false; + } +} + +MVHDGeom mvhd_calculate_geometry(uint64_t size) { + MVHDGeom chs; + uint32_t ts = (uint32_t)(size / MVHD_SECTOR_SIZE); + uint32_t spt, heads, cyl, cth; + if (ts > 65535 * 16 * 255) { + ts = 65535 * 16 * 255; + } + if (ts >= 65535 * 16 * 63) { + spt = 255; + heads = 16; + cth = ts / spt; + } else { + spt = 17; + cth = ts / spt; + heads = (cth + 1023) / 1024; + if (heads < 4) { + heads = 4; + } + if (cth >= (heads * 1024) || heads > 16) { + spt = 31; + heads = 16; + cth = ts / spt; + } + if (cth >= (heads * 1024)) { + spt = 63; + heads = 16; + cth = ts / spt; + } + } + cyl = cth / heads; + chs.heads = heads; + chs.spt = spt; + chs.cyl = cyl; + return chs; +} + +MVHDMeta* mvhd_open(const char* path, bool readonly, int* err) { + MVHDError open_err; + MVHDMeta *vhdm = calloc(sizeof *vhdm, 1); + if (vhdm == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + if (strlen(path) >= sizeof vhdm->filename) { + *err = MVHD_ERR_PATH_LEN; + goto cleanup_vhdm; + } + //This is safe, as we've just checked for potential overflow above + strcpy(vhdm->filename, path); + vhdm->f = readonly ? mvhd_fopen((const char*)vhdm->filename, "rb", err) : mvhd_fopen((const char*)vhdm->filename, "rb+", err); + if (vhdm->f == NULL) { + /* note, mvhd_fopen sets err for us */ + goto cleanup_vhdm; + } + vhdm->readonly = readonly; + if (!mvhd_file_is_vhd(vhdm->f)) { + *err = MVHD_ERR_NOT_VHD; + goto cleanup_file; + } + mvhd_read_footer(vhdm); + if (!mvhd_footer_checksum_valid(vhdm)) { + *err = MVHD_ERR_FOOTER_CHECKSUM; + goto cleanup_file; + } + if (vhdm->footer.disk_type == MVHD_TYPE_DIFF || vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) { + mvhd_read_sparse_header(vhdm); + if (!mvhd_sparse_checksum_valid(vhdm)) { + *err = MVHD_ERR_SPARSE_CHECKSUM; + goto cleanup_file; + } + if (mvhd_read_bat(vhdm, &open_err) == -1) { + *err = open_err; + goto cleanup_file; + } + mvhd_calc_sparse_values(vhdm); + if (mvhd_init_sector_bitmap(vhdm, &open_err) == -1) { + *err = open_err; + goto cleanup_bat; + } + + } else if (vhdm->footer.disk_type != MVHD_TYPE_FIXED) { + *err = MVHD_ERR_TYPE; + goto cleanup_bitmap; + } + mvhd_assign_io_funcs(vhdm); + vhdm->format_buffer.zero_data = calloc(64, MVHD_SECTOR_SIZE); + if (vhdm->format_buffer.zero_data == NULL) { + *err = MVHD_ERR_MEM; + goto cleanup_bitmap; + } + vhdm->format_buffer.sector_count = 64; + if (vhdm->footer.disk_type == MVHD_TYPE_DIFF) { + char* par_path = mvhd_get_diff_parent_path(vhdm, err); + if (par_path == NULL) { + goto cleanup_format_buff; + } + uint32_t par_mod_ts = mvhd_file_mod_timestamp(par_path, err); + if (*err != 0) { + goto cleanup_format_buff; + } + if (vhdm->sparse.par_timestamp != par_mod_ts) { + /* The last-modified timestamp is to fragile to make this a fatal error. + Instead, we inform the caller of the potential problem. */ + *err = MVHD_ERR_TIMESTAMP; + } + vhdm->parent = mvhd_open(par_path, true, err); + if (vhdm->parent == NULL) { + goto cleanup_format_buff; + } + if (memcmp(vhdm->sparse.par_uuid, vhdm->parent->footer.uuid, sizeof vhdm->sparse.par_uuid) != 0) { + *err = MVHD_ERR_INVALID_PAR_UUID; + goto cleanup_format_buff; + } + } + /* If we've reached this point, we are good to go, so skip the cleanup steps */ + goto end; +cleanup_format_buff: + free(vhdm->format_buffer.zero_data); + vhdm->format_buffer.zero_data = NULL; +cleanup_bitmap: + free(vhdm->bitmap.curr_bitmap); + vhdm->bitmap.curr_bitmap = NULL; +cleanup_bat: + free(vhdm->block_offset); + vhdm->block_offset = NULL; +cleanup_file: + fclose(vhdm->f); + vhdm->f = NULL; +cleanup_vhdm: + free(vhdm); + vhdm = NULL; +end: + return vhdm; +} + +void mvhd_close(MVHDMeta* vhdm) { + if (vhdm != NULL) { + if (vhdm->parent != NULL) { + mvhd_close(vhdm->parent); + } + fclose(vhdm->f); + if (vhdm->block_offset != NULL) { + free(vhdm->block_offset); + vhdm->block_offset = NULL; + } + if (vhdm->bitmap.curr_bitmap != NULL) { + free(vhdm->bitmap.curr_bitmap); + vhdm->bitmap.curr_bitmap = NULL; + } + if (vhdm->format_buffer.zero_data != NULL) { + free(vhdm->format_buffer.zero_data); + vhdm->format_buffer.zero_data = NULL; + } + free(vhdm); + vhdm = NULL; + } +} + +int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err) { + uint8_t sparse_buff[1024]; + if (vhdm == NULL || err == NULL) { + *err = MVHD_ERR_INVALID_PARAMS; + return -1; + } + if (vhdm->footer.disk_type != MVHD_TYPE_DIFF) { + *err = MVHD_ERR_TYPE; + return -1; + } + char* par_path = mvhd_get_diff_parent_path(vhdm, err); + if (par_path == NULL) { + return -1; + } + uint32_t par_mod_ts = mvhd_file_mod_timestamp(par_path, err); + if (*err != 0) { + return -1; + } + /* Update the timestamp and sparse header checksum */ + vhdm->sparse.par_timestamp = par_mod_ts; + vhdm->sparse.checksum = mvhd_gen_sparse_checksum(&vhdm->sparse); + /* Generate and write the updated sparse header */ + mvhd_header_to_buffer(&vhdm->sparse, sparse_buff); + mvhd_fseeko64(vhdm->f, (int64_t)vhdm->footer.data_offset, SEEK_SET); + fwrite(sparse_buff, sizeof sparse_buff, 1, vhdm->f); + return 0; +} + +int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + return vhdm->read_sectors(vhdm, offset, num_sectors, out_buff); +} + +int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + return vhdm->write_sectors(vhdm, offset, num_sectors, in_buff); +} + +int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors) { + int num_full = num_sectors / vhdm->format_buffer.sector_count; + int remain = num_sectors % vhdm->format_buffer.sector_count; + for (int i = 0; i < num_full; i++) { + vhdm->write_sectors(vhdm, offset, vhdm->format_buffer.sector_count, vhdm->format_buffer.zero_data); + offset += vhdm->format_buffer.sector_count; + } + vhdm->write_sectors(vhdm, offset, remain, vhdm->format_buffer.zero_data); + return 0; +} \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_struct_rw.c b/src/disk/minivhd/minivhd_struct_rw.c new file mode 100644 index 000000000..66f2289af --- /dev/null +++ b/src/disk/minivhd/minivhd_struct_rw.c @@ -0,0 +1,165 @@ +/** + * \file + * \brief Header and footer serialize/deserialize functions + */ + +#include +#include +#include +#include +#include +#include "minivhd_util.h" +#include "minivhd_internal.h" + +/* Read data from footer into the struct members, swapping endian where necessary + Note: order matters here! We must read each field in the order the struct is in. + Doing this may be less elegant than performing a memcpy to a packed struct, but + it avoids potential data alignment issues, and the endian swapping allows us to + use the fields directly. */ + +static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer); +static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer); + +/** + * \brief Get the next field from a buffer and store it in a struct member, converting endian if necessary + * + * \param [out] struct_memb struct member to save the field to + * \param [in] memb_size the size of struct_memb, in bytes + * \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32) + * \param [in] buffer the buffer from which fields are read from. Will be advanced at the end of the function call + */ +static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) { + memcpy(struct_memb, *buffer, memb_size); + if (req_endian) { + switch (memb_size) { + case 2: + *(uint16_t*)(struct_memb) = mvhd_from_be16(*(uint16_t*)(struct_memb)); + break; + case 4: + *(uint32_t*)(struct_memb) = mvhd_from_be32(*(uint32_t*)(struct_memb)); + break; + case 8: + *(uint64_t*)(struct_memb) = mvhd_from_be64(*(uint64_t*)(struct_memb)); + break; + } + } + *buffer += memb_size; +} + +/** + * \brief Save a struct member into a buffer, converting endian if necessary + * + * \param [in] struct_memb struct member read from + * \param [in] memb_size the size of struct_memb, in bytes + * \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32) + * \param [out] buffer the buffer from which struct member is saved to. Will be advanced at the end of the function call + */ +static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) { + uint8_t *buf_ptr = *buffer; + memcpy(buf_ptr, struct_memb, memb_size); + if (req_endian) { + switch (memb_size) { + case 2: + *((uint16_t*)buf_ptr) = mvhd_to_be16(*(uint16_t*)(struct_memb)); + break; + case 4: + *((uint32_t*)buf_ptr) = mvhd_to_be32(*(uint32_t*)(struct_memb)); + break; + case 8: + *((uint64_t*)buf_ptr) = mvhd_to_be64(*(uint64_t*)(struct_memb)); + break; + } + } + buf_ptr += memb_size; + *buffer = buf_ptr; +} + +void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_buffer_to_struct(&footer->cookie, sizeof footer->cookie, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->features, sizeof footer->features, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->checksum, sizeof footer->checksum, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->uuid, sizeof footer->uuid, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->reserved, sizeof footer->reserved, false, &buff_ptr); +} + +void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_struct_to_buffer(&footer->cookie, sizeof footer->cookie, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->features, sizeof footer->features, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->checksum, sizeof footer->checksum, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->uuid, sizeof footer->uuid, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->reserved, sizeof footer->reserved, false, &buff_ptr); +} + +void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_buffer_to_struct(&header->cookie, sizeof header->cookie, false, &buff_ptr); + mvhd_next_buffer_to_struct(&header->data_offset, sizeof header->data_offset, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->head_vers, sizeof header->head_vers, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->block_sz, sizeof header->block_sz, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->checksum, sizeof header->checksum, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr); + for (int i = 0; i < 8; i++) { + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr); + } + mvhd_next_buffer_to_struct(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr); +} + +void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_struct_to_buffer(&header->cookie, sizeof header->cookie, false, &buff_ptr); + mvhd_next_struct_to_buffer(&header->data_offset, sizeof header->data_offset, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->head_vers, sizeof header->head_vers, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->block_sz, sizeof header->block_sz, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->checksum, sizeof header->checksum, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr); + for (int i = 0; i < 8; i++) { + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr); + } + mvhd_next_struct_to_buffer(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr); +} \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_struct_rw.h b/src/disk/minivhd/minivhd_struct_rw.h new file mode 100644 index 000000000..0b1e0181f --- /dev/null +++ b/src/disk/minivhd/minivhd_struct_rw.h @@ -0,0 +1,38 @@ +#ifndef MINIVHD_STRUCT_RW_H +#define minivhd_struct_rw + +#include "minivhd_internal.h" + +/** + * \brief Save the contents of a VHD footer from a buffer to a struct + * + * \param [out] footer save contents of buffer into footer + * \param [in] buffer VHD footer in raw bytes + */ +void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer); + +/** + * \brief Save the contents of a VHD sparse header from a buffer to a struct + * + * \param [out] header save contents of buffer into header + * \param [in] buffer VHD header in raw bytes + */ +void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer); + +/** + * \brief Save the contents of a VHD footer struct to a buffer + * + * \param [in] footer save contents of struct into buffer + * \param [out] buffer VHD footer in raw bytes + */ +void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer); + +/** + * \brief Save the contents of a VHD sparse header struct to a buffer + * + * \param [in] header save contents of struct into buffer + * \param [out] buffer VHD sparse header in raw bytes + */ +void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer); + +#endif \ No newline at end of file diff --git a/src/disk/minivhd/minivhd_util.c b/src/disk/minivhd/minivhd_util.c new file mode 100644 index 000000000..d8f44cad0 --- /dev/null +++ b/src/disk/minivhd/minivhd_util.c @@ -0,0 +1,323 @@ +/** + * \file + * \brief Utility functions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libxml2_encoding.h" +#include "minivhd_internal.h" +#include "minivhd_util.h" + +const char MVHD_CONECTIX_COOKIE[] = "conectix"; +const char MVHD_CREATOR[] = "pcem"; +const char MVHD_CREATOR_HOST_OS[] = "Wi2k"; +const char MVHD_CXSPARSE_COOKIE[] = "cxsparse"; + +uint16_t mvhd_from_be16(uint16_t val) { + uint8_t *tmp = (uint8_t*)&val; + uint16_t ret = 0; + ret |= (uint16_t)tmp[0] << 8; + ret |= (uint16_t)tmp[1] << 0; + return ret; +} +uint32_t mvhd_from_be32(uint32_t val) { + uint8_t *tmp = (uint8_t*)&val; + uint32_t ret = 0; + ret = (uint32_t)tmp[0] << 24; + ret |= (uint32_t)tmp[1] << 16; + ret |= (uint32_t)tmp[2] << 8; + ret |= (uint32_t)tmp[3] << 0; + return ret; +} +uint64_t mvhd_from_be64(uint64_t val) { + uint8_t *tmp = (uint8_t*)&val; + uint64_t ret = 0; + ret = (uint64_t)tmp[0] << 56; + ret |= (uint64_t)tmp[1] << 48; + ret |= (uint64_t)tmp[2] << 40; + ret |= (uint64_t)tmp[3] << 32; + ret |= (uint64_t)tmp[4] << 24; + ret |= (uint64_t)tmp[5] << 16; + ret |= (uint64_t)tmp[6] << 8; + ret |= (uint64_t)tmp[7] << 0; + return ret; +} +uint16_t mvhd_to_be16(uint16_t val) { + uint16_t ret = 0; + uint8_t *tmp = (uint8_t*)&ret; + tmp[0] = (val & 0xff00) >> 8; + tmp[1] = (val & 0x00ff) >> 0; + return ret; +} +uint32_t mvhd_to_be32(uint32_t val) { + uint32_t ret = 0; + uint8_t *tmp = (uint8_t*)&ret; + tmp[0] = (val & 0xff000000) >> 24; + tmp[1] = (val & 0x00ff0000) >> 16; + tmp[2] = (val & 0x0000ff00) >> 8; + tmp[3] = (val & 0x000000ff) >> 0; + return ret; +} +uint64_t mvhd_to_be64(uint64_t val) { + uint64_t ret = 0; + uint8_t *tmp = (uint8_t*)&ret; + tmp[0] = (uint8_t)((val & 0xff00000000000000) >> 56); + tmp[1] = (uint8_t)((val & 0x00ff000000000000) >> 48); + tmp[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40); + tmp[3] = (uint8_t)((val & 0x000000ff00000000) >> 32); + tmp[4] = (uint8_t)((val & 0x00000000ff000000) >> 24); + tmp[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16); + tmp[6] = (uint8_t)((val & 0x000000000000ff00) >> 8); + tmp[7] = (uint8_t)((val & 0x00000000000000ff) >> 0); + return ret; +} + +bool mvhd_is_conectix_str(const void* buffer) { + if (strncmp(buffer, MVHD_CONECTIX_COOKIE, strlen(MVHD_CONECTIX_COOKIE)) == 0) { + return true; + } else { + return false; + } +} + +void mvhd_generate_uuid(uint8_t* uuid) +{ + /* We aren't doing crypto here, so using system time as seed should be good enough */ + srand((unsigned int)time(0)); + for (int n = 0; n < 16; n++) { + uuid[n] = rand(); + } + uuid[6] &= 0x0F; + uuid[6] |= 0x40; /* Type 4 */ + uuid[8] &= 0x3F; + uuid[8] |= 0x80; /* Variant 1 */ +} + +uint32_t vhd_calc_timestamp(void) +{ + time_t start_time; + time_t curr_time; + double vhd_time; + start_time = MVHD_START_TS; /* 1 Jan 2000 00:00 */ + curr_time = time(NULL); + vhd_time = difftime(curr_time, start_time); + return (uint32_t)vhd_time; +} + +uint32_t mvhd_epoch_to_vhd_ts(time_t ts) { + time_t start_time = MVHD_START_TS; + if (ts < start_time) { + return start_time; + } + double vhd_time = difftime(ts, start_time); + return (uint32_t)vhd_time; +} + +time_t vhd_get_created_time(MVHDMeta *vhdm) +{ + time_t vhd_time = (time_t)vhdm->footer.timestamp; + time_t vhd_time_unix = MVHD_START_TS + vhd_time; + return vhd_time_unix; +} + +FILE* mvhd_fopen(const char* path, const char* mode, int* err) { + FILE* f = NULL; +#ifdef _WIN32 + size_t path_len = strlen(path); + size_t mode_len = strlen(mode); + mvhd_utf16 new_path[260] = {0}; + int new_path_len = (sizeof new_path) - 2; + mvhd_utf16 mode_str[5] = {0}; + int new_mode_len = (sizeof mode_str) - 2; + int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len); + int mode_res = UTF8ToUTF16LE((unsigned char*)mode_str, &new_mode_len, (const unsigned char*)mode, (int*)&mode_len); + if (path_res > 0 && mode_res > 0) { + f = _wfopen(new_path, mode_str); + if (f == NULL) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + } + } else { + if (path_res == -1 || mode_res == -1) { + *err = MVHD_ERR_UTF_SIZE; + } else if (path_res == -2 || mode_res == -2) { + *err = MVHD_ERR_UTF_TRANSCODING_FAILED; + } + } +#else + f = fopen64(path, mode); + if (f == NULL) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + } +#endif + return f; +} + +void mvhd_set_encoding_err(int encoding_retval, int* err) { + if (encoding_retval == -1) { + *err = MVHD_ERR_UTF_SIZE; + } else if (encoding_retval == -2) { + *err = MVHD_ERR_UTF_TRANSCODING_FAILED; + } +} + +uint64_t mvhd_calc_size_bytes(MVHDGeom *geom) { + uint64_t img_size = (uint64_t)geom->cyl * (uint64_t)geom->heads * (uint64_t)geom->spt * (uint64_t)MVHD_SECTOR_SIZE; + return img_size; +} + +uint32_t mvhd_calc_size_sectors(MVHDGeom *geom) { + uint32_t sector_size = (uint32_t)geom->cyl * (uint32_t)geom->heads * (uint32_t)geom->spt; + return sector_size; +} + +MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm) { + MVHDGeom geometry = { .cyl = vhdm->footer.geom.cyl, .heads = vhdm->footer.geom.heads, .spt = vhdm->footer.geom.spt }; + return geometry; +} + +uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer) { + uint32_t new_chk = 0; + uint32_t orig_chk = footer->checksum; + footer->checksum = 0; + uint8_t* footer_bytes = (uint8_t*)footer; + for (size_t i = 0; i < sizeof *footer; i++) { + new_chk += footer_bytes[i]; + } + footer->checksum = orig_chk; + return ~new_chk; +} + +uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header) { + uint32_t new_chk = 0; + uint32_t orig_chk = header->checksum; + header->checksum = 0; + uint8_t* sparse_bytes = (uint8_t*)header; + for (size_t i = 0; i < sizeof *header; i++) { + new_chk += sparse_bytes[i]; + } + header->checksum = orig_chk; + return ~new_chk; +} + +const char* mvhd_strerr(MVHDError err) { + switch (err) { + case MVHD_ERR_MEM: + return "memory allocation error"; + case MVHD_ERR_FILE: + return "file error"; + case MVHD_ERR_NOT_VHD: + return "file is not a VHD image"; + case MVHD_ERR_TYPE: + return "unsupported VHD image type"; + case MVHD_ERR_FOOTER_CHECKSUM: + return "invalid VHD footer checksum"; + case MVHD_ERR_SPARSE_CHECKSUM: + return "invalid VHD sparse header checksum"; + case MVHD_ERR_UTF_TRANSCODING_FAILED: + return "error converting path encoding"; + case MVHD_ERR_UTF_SIZE: + return "buffer size mismatch when converting path encoding"; + case MVHD_ERR_PATH_REL: + return "relative path detected where absolute path expected"; + case MVHD_ERR_PATH_LEN: + return "path length exceeds MVHD_MAX_PATH"; + case MVHD_ERR_PAR_NOT_FOUND: + return "parent VHD image not found"; + case MVHD_ERR_INVALID_PAR_UUID: + return "UUID mismatch between child and parent VHD"; + case MVHD_ERR_INVALID_GEOM: + return "invalid geometry detected"; + case MVHD_ERR_INVALID_SIZE: + return "invalid size"; + case MVHD_ERR_INVALID_BLOCK_SIZE: + return "invalid block size"; + case MVHD_ERR_INVALID_PARAMS: + return "invalid parameters passed to function"; + case MVHD_ERR_CONV_SIZE: + return "error converting image. Size mismatch detechted"; + default: + return "unknown error"; + } +} + +int64_t mvhd_ftello64(FILE* stream) +{ +#ifdef _MSC_VER + return _ftelli64(stream); +#else + return ftello64(stream); +#endif +} + +int mvhd_fseeko64(FILE* stream, int64_t offset, int origin) +{ +#ifdef _MSC_VER + return _fseeki64(stream, offset, origin); +#else + return fseeko64(stream, offset, origin); +#endif +} + +uint32_t mvhd_crc32_for_byte(uint32_t r) { + for (int j = 0; j < 8; ++j) + r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1; + return r ^ (uint32_t)0xFF000000L; +} + +uint32_t mvhd_crc32(const void* data, size_t n_bytes) { + static uint32_t table[0x100]; + if (!*table) + for (size_t i = 0; i < 0x100; ++i) + table[i] = mvhd_crc32_for_byte(i); + + uint32_t crc = 0; + for (size_t i = 0; i < n_bytes; ++i) + crc = table[(uint8_t)crc ^ ((uint8_t*)data)[i]] ^ crc >> 8; + + return crc; +} + +uint32_t mvhd_file_mod_timestamp(const char* path, int *err) { + *err = 0; +#ifdef _WIN32 + struct _stat file_stat; + size_t path_len = strlen(path); + mvhd_utf16 new_path[260] = {0}; + int new_path_len = (sizeof new_path) - 2; + int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len); + if (path_res > 0) { + int stat_res = _wstat(new_path, &file_stat); + if (stat_res != 0) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + return 0; + } + return mvhd_epoch_to_vhd_ts(file_stat.st_mtime); + } else { + if (path_res == -1) { + *err = MVHD_ERR_UTF_SIZE; + } else if (path_res == -2) { + *err = MVHD_ERR_UTF_TRANSCODING_FAILED; + } + return 0; + } +#else + struct stat file_stat; + int stat_res = stat(path, &file_stat); + if (stat_res != 0) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + return 0; + } + return mvhd_epoch_to_vhd_ts(file_stat.st_mtime); +#endif +} diff --git a/src/disk/minivhd/minivhd_util.h b/src/disk/minivhd/minivhd_util.h new file mode 100644 index 000000000..df6841009 --- /dev/null +++ b/src/disk/minivhd/minivhd_util.h @@ -0,0 +1,136 @@ +#ifndef MINIVHD_UTIL_H +#define MINIVHD_UTIL_H + +#include +#include +#include +#include "minivhd_internal.h" +#include "minivhd.h" +#define MVHD_START_TS 946684800 + +/** + * Functions to deal with endian issues + */ +uint16_t mvhd_from_be16(uint16_t val); +uint32_t mvhd_from_be32(uint32_t val); +uint64_t mvhd_from_be64(uint64_t val); +uint16_t mvhd_to_be16(uint16_t val); +uint32_t mvhd_to_be32(uint32_t val); +uint64_t mvhd_to_be64(uint64_t val); + +/** + * \brief Check if provided buffer begins with the string "conectix" + * + * \param [in] buffer The buffer to compare. Must be at least 8 bytes in length + * + * \return true if the buffer begins with "conectix" + * \return false if the buffer does not begin with "conectix" + */ +bool mvhd_is_conectix_str(const void* buffer); + +/** + * \brief Generate a raw 16 byte UUID + * + * \param [out] uuid A 16 byte buffer in which the generated UUID will be stored to + */ +void mvhd_generate_uuid(uint8_t *uuid); + +/** + * \brief Calculate a VHD formatted timestamp from the current time + */ +uint32_t vhd_calc_timestamp(void); + +/** + * \brief Convert an epoch timestamp to a VHD timestamp + * + * \param [in] ts epoch timestamp to convert. + * + * \return The adjusted timestamp, or 0 if the input timestamp is + * earlier that 1 Janurary 2000 + */ +uint32_t mvhd_epoch_to_vhd_ts(time_t ts); + +/** + * \brief Return the created time from a VHD image + * + * \param [in] vhdm Pointer to the MiniVHD metadata structure + * + * \return The created time, as a Unix timestamp + */ +time_t vhd_get_created_time(MVHDMeta *vhdm); + +/** + * \brief Cross platform, unicode filepath opening + * + * This function accounts for the fact that fopen() handles file paths differently compared to other + * operating systems. Windows version of fopen() will not handle multi byte encoded text like UTF-8. + * + * Unicode filepath support on Windows requires using the _wfopen() function, which expects UTF-16LE + * encoded path and modestring. + * + * \param [in] path The filepath to open as a UTF-8 string + * \param [in] mode The mode string to use (eg: "rb+"") + * \param [out] err The error value, if an error occurrs + * + * \return a FILE pointer if successful, NULL otherwise. If NULL, check the value of err + */ +FILE* mvhd_fopen(const char* path, const char* mode, int* err); + +void mvhd_set_encoding_err(int encoding_retval, int* err); +uint64_t mvhd_calc_size_bytes(MVHDGeom *geom); +uint32_t mvhd_calc_size_sectors(MVHDGeom *geom); +MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm); + +/** + * \brief Generate VHD footer checksum + * + * \param [in] vhdm MiniVHD data structure + */ +uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer); + +/** + * \brief Generate VHD sparse header checksum + * + * \param [in] vhdm MiniVHD data structure + */ +uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header); + +/** + * \brief Get current position in file stream + * + * This is a portable version of the POSIX ftello64(). * + */ +int64_t mvhd_ftello64(FILE* stream); + +/** + * \brief Reposition the file stream's position + * + * This is a portable version of the POSIX fseeko64(). * + */ +int mvhd_fseeko64(FILE* stream, int64_t offset, int origin); + +/** + * \brief Calculate the CRC32 of a data buffer. + * + * This function can be used for verifying data integrity. + * + * \param [in] data The data buffer + * \param [in] n_bytes The size of the data buffer in bytes + * + * \return The CRC32 of the data buffer + */ +uint32_t mvhd_crc32(const void* data, size_t n_bytes); + +/** + * \brief Calculate the file modification timestamp. + * + * This function is primarily to help protect differencing VHD's + * + * \param [in] path the UTF-8 file path + * \param [out] err The error value, if an error occurrs + * + * \return The file modified timestamp, in VHD compatible timestamp. + * 'err' will be set to non-zero on error + */ +uint32_t mvhd_file_mod_timestamp(const char* path, int *err); +#endif diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index ffe6b66bf..f411e2412 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -303,7 +303,7 @@ endif # Nothing should need changing from here on.. # ######################################################################### VPATH := $(EXPATH) . $(CODEGEN) cpu \ - cdrom chipset device disk floppy \ + cdrom chipset device disk disk/minivhd floppy \ game machine mem printer \ sio sound \ sound/munt sound/munt/c_interface sound/munt/sha1 \ @@ -690,6 +690,10 @@ HDDOBJ := hdd.o \ hdc_xtide.o hdc_ide.o \ hdc_ide_opti611.o \ hdc_ide_cmd640.o hdc_ide_sff8038i.o + +MINIVHDOBJ := cwalk.o libxml2_encoding.o minivhd_convert.o \ + minivhd_create.o minivhd_io.o minivhd_manage.o \ + minivhd_struct_rw.o minivhd_util.o CDROMOBJ := cdrom.o \ cdrom_image_backend.o cdrom_image.o @@ -789,7 +793,7 @@ else endif OBJ := $(MAINOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) $(DEVOBJ) $(MEMOBJ) \ - $(FDDOBJ) $(GAMEOBJ) $(CDROMOBJ) $(ZIPOBJ) $(MOOBJ) $(HDDOBJ) \ + $(FDDOBJ) $(GAMEOBJ) $(CDROMOBJ) $(ZIPOBJ) $(MOOBJ) $(HDDOBJ) $(MINIVHDOBJ) \ $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SIOOBJ) $(SNDOBJ) $(VIDOBJ) \ $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) $(DEVBROBJ) \ $(DISCORDOBJ) From 3085b1579f628b853ab79994044d3cd096c34ee3 Mon Sep 17 00:00:00 2001 From: Stephen McKinney Date: Tue, 17 Nov 2020 00:42:52 -0600 Subject: [PATCH 02/67] Remove existing VHD code. --- src/disk/hdd_image.c | 338 ++-------------------------------------- src/include/86box/hdd.h | 31 ---- src/win/win_settings.c | 32 +--- 3 files changed, 18 insertions(+), 383 deletions(-) diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index aa8bf8509..621e2f86c 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -49,27 +49,6 @@ hdd_image_t hdd_images[HDD_NUM]; static char empty_sector[512]; static char *empty_sector_1mb; - -#define VHD_OFFSET_COOKIE 0 -#define VHD_OFFSET_FEATURES 8 -#define VHD_OFFSET_VERSION 12 -#define VHD_OFFSET_DATA_OFFSET 16 -#define VHD_OFFSET_TIMESTAMP 24 -#define VHD_OFFSET_CREATOR 28 -#define VHD_OFFSET_CREATOR_VERS 32 -#define VHD_OFFSET_CREATOR_HOST 36 -#define VHD_OFFSET_ORIG_SIZE 40 -#define VHD_OFFSET_CURR_SIZE 48 -#define VHD_OFFSET_GEOM_CYL 56 -#define VHD_OFFSET_GEOM_HEAD 58 -#define VHD_OFFSET_GEOM_SPT 59 -#define VHD_OFFSET_TYPE 60 -#define VHD_OFFSET_CHECKSUM 64 -#define VHD_OFFSET_UUID 68 -#define VHD_OFFSET_SAVED_STATE 84 -#define VHD_OFFSET_RESERVED 85 - - #ifdef ENABLE_HDD_IMAGE_LOG int hdd_image_do_log = ENABLE_HDD_IMAGE_LOG; @@ -152,10 +131,7 @@ image_is_hdx(const wchar_t *s, int check_signature) int image_is_vhd(const wchar_t *s, int check_signature) { - int len; - FILE *f; - uint64_t filelen; - uint64_t signature; + int len; char *ws = (char *) s; wchar_t ext[5] = { 0, 0, 0, 0, 0 }; len = wcslen(s); @@ -164,257 +140,16 @@ image_is_vhd(const wchar_t *s, int check_signature) memcpy(ext, ws + ((len - 4) << 1), 8); if (wcscasecmp(ext, L".VHD") == 0) { if (check_signature) { - f = plat_fopen((wchar_t *)s, L"rb"); - if (!f) - return 0; - fseeko64(f, 0, SEEK_END); - filelen = ftello64(f); - if (fseeko64(f, -512, SEEK_END) == -1) { - fclose(f); - fatal("image_is_vhd(): Error seeking\n"); - } - if (filelen < 512) { - if (f != NULL) - fclose(f); - return 0; - } - if (fread(&signature, 1, 8, f) != 8) - fatal("image_is_vhd(): Error reading signature\n"); - fclose(f); - if (signature == 0x78697463656E6F63ll) + // if is VHD return 1; - else - return 0; + // else + // return 0; } else return 1; } else return 0; } - -static uint64_t -be_to_u64(uint8_t *bytes, int start) -{ - uint64_t n = ((uint64_t) bytes[start + 7] << 0) | - ((uint64_t) bytes[start + 6] << 8) | - ((uint64_t) bytes[start + 5] << 16) | - ((uint64_t) bytes[start + 4] << 24) | - ((uint64_t) bytes[start + 3] << 32) | - ((uint64_t) bytes[start + 2] << 40) | - ((uint64_t) bytes[start + 1] << 48) | - ((uint64_t) bytes[start ] << 56); - return n; -} - - -static uint32_t -be_to_u32(uint8_t *bytes, int start) -{ - uint32_t n = ((uint32_t) bytes[start + 3] << 0) | - ((uint32_t) bytes[start + 2] << 8) | - ((uint32_t) bytes[start + 1] << 16) | - ((uint32_t) bytes[start ] << 24); - return n; -} - - -static uint16_t -be_to_u16(uint8_t *bytes, int start) -{ - uint16_t n = ((uint16_t) bytes[start + 1] << 0) | - ((uint16_t) bytes[start ] << 8); - return n; -} - - -static uint64_t -u64_to_be(uint64_t value, int is_be) -{ - uint64_t res = 0; - if (is_be) - res = value; - else { - uint64_t mask = 0xff00000000000000; - res = ((value & (mask >> 0)) >> 56) | - ((value & (mask >> 8)) >> 40) | - ((value & (mask >> 16)) >> 24) | - ((value & (mask >> 24)) >> 8) | - ((value & (mask >> 32)) << 8) | - ((value & (mask >> 40)) << 24) | - ((value & (mask >> 48)) << 40) | - ((value & (mask >> 56)) << 56); - } - return res; -} - - -static uint32_t -u32_to_be(uint32_t value, int is_be) -{ - uint32_t res = 0; - if (is_be) - res = value; - else { - uint32_t mask = 0xff000000; - res = ((value & (mask >> 0)) >> 24) | - ((value & (mask >> 8)) >> 8) | - ((value & (mask >> 16)) << 8) | - ((value & (mask >> 24)) << 24); - } - return res; -} - - -static uint16_t -u16_to_be(uint16_t value, int is_be) -{ - uint16_t res = 0; - if (is_be) - res = value; - else - res = (value >> 8) | (value << 8); - - return res; -} - - -static void -mk_guid(uint8_t *guid) -{ - int n; - - for (n = 0; n < 16; n++) - guid[n] = random_generate(); - - guid[6] &= 0x0F; - guid[6] |= 0x40; /* Type 4 */ - guid[8] &= 0x3F; - guid[8] |= 0x80; /* Variant 1 */ -} - - -static uint32_t -calc_vhd_timestamp() -{ - time_t start_time; - time_t curr_time; - double vhd_time; - start_time = 946684800; /* 1 Jan 2000 00:00 */ - curr_time = time(NULL); - vhd_time = difftime(curr_time, start_time); - - return (uint32_t)vhd_time; -} - - -void -vhd_footer_from_bytes(vhd_footer_t *vhd, uint8_t *bytes) -{ - memcpy(vhd->cookie, bytes + VHD_OFFSET_COOKIE, sizeof(vhd->cookie)); - vhd->features = be_to_u32(bytes, VHD_OFFSET_FEATURES); - vhd->version = be_to_u32(bytes, VHD_OFFSET_VERSION); - vhd->offset = be_to_u64(bytes, VHD_OFFSET_DATA_OFFSET); - vhd->timestamp = be_to_u32(bytes, VHD_OFFSET_TIMESTAMP); - memcpy(vhd->creator, bytes + VHD_OFFSET_CREATOR, sizeof(vhd->creator)); - vhd->creator_vers = be_to_u32(bytes, VHD_OFFSET_CREATOR_VERS); - memcpy(vhd->creator_host_os, bytes + VHD_OFFSET_CREATOR_HOST, sizeof(vhd->creator_host_os)); - vhd->orig_size = be_to_u64(bytes, VHD_OFFSET_ORIG_SIZE); - vhd->curr_size = be_to_u64(bytes, VHD_OFFSET_CURR_SIZE); - vhd->geom.cyl = be_to_u16(bytes, VHD_OFFSET_GEOM_CYL); - vhd->geom.heads = bytes[VHD_OFFSET_GEOM_HEAD]; - vhd->geom.spt = bytes[VHD_OFFSET_GEOM_SPT]; - vhd->type = be_to_u32(bytes, VHD_OFFSET_TYPE); - vhd->checksum = be_to_u32(bytes, VHD_OFFSET_CHECKSUM); - memcpy(vhd->uuid, bytes + VHD_OFFSET_UUID, sizeof(vhd->uuid)); /* TODO: handle UUID's properly */ - vhd->saved_state = bytes[VHD_OFFSET_SAVED_STATE]; - memcpy(vhd->reserved, bytes + VHD_OFFSET_RESERVED, sizeof(vhd->reserved)); -} - - -void -vhd_footer_to_bytes(uint8_t *bytes, vhd_footer_t *vhd) -{ - /* Quick endian check */ - int is_be = 0; - uint8_t e = 1; - uint8_t *ep = &e; - uint16_t u16; - uint32_t u32; - uint64_t u64; - - if (ep[0] == 0) - is_be = 1; - - memcpy(bytes + VHD_OFFSET_COOKIE, vhd->cookie, sizeof(vhd->cookie)); - u32 = u32_to_be(vhd->features, is_be); - memcpy(bytes + VHD_OFFSET_FEATURES, &u32, sizeof(vhd->features)); - u32 = u32_to_be(vhd->version, is_be); - memcpy(bytes + VHD_OFFSET_VERSION, &u32, sizeof(vhd->version)); - u64 = u64_to_be(vhd->offset, is_be); - memcpy(bytes + VHD_OFFSET_DATA_OFFSET, &u64, sizeof(vhd->offset)); - u32 = u32_to_be(vhd->timestamp, is_be); - memcpy(bytes + VHD_OFFSET_TIMESTAMP, &u32, sizeof(vhd->timestamp)); - memcpy(bytes + VHD_OFFSET_CREATOR, vhd->creator, sizeof(vhd->creator)); - u32 = u32_to_be(vhd->creator_vers, is_be); - memcpy(bytes + VHD_OFFSET_CREATOR_VERS, &u32, sizeof(vhd->creator_vers)); - memcpy(bytes + VHD_OFFSET_CREATOR_HOST, vhd->creator_host_os, sizeof(vhd->creator_host_os)); - u64 = u64_to_be(vhd->orig_size, is_be); - memcpy(bytes + VHD_OFFSET_ORIG_SIZE, &u64, sizeof(vhd->orig_size)); - u64 = u64_to_be(vhd->curr_size, is_be); - memcpy(bytes + VHD_OFFSET_CURR_SIZE, &u64, sizeof(vhd->curr_size)); - u16 = u16_to_be(vhd->geom.cyl, is_be); - memcpy(bytes + VHD_OFFSET_GEOM_CYL, &u16, sizeof(vhd->geom.cyl)); - memcpy(bytes + VHD_OFFSET_GEOM_HEAD, &(vhd->geom.heads), sizeof(vhd->geom.heads)); - memcpy(bytes + VHD_OFFSET_GEOM_SPT, &(vhd->geom.spt), sizeof(vhd->geom.spt)); - u32 = u32_to_be(vhd->type, is_be); - memcpy(bytes + VHD_OFFSET_TYPE, &u32, sizeof(vhd->type)); - u32 = u32_to_be(vhd->checksum, is_be); - memcpy(bytes + VHD_OFFSET_CHECKSUM, &u32, sizeof(vhd->checksum)); - memcpy(bytes + VHD_OFFSET_UUID, vhd->uuid, sizeof(vhd->uuid)); - memcpy(bytes + VHD_OFFSET_SAVED_STATE, &(vhd->saved_state), sizeof(vhd->saved_state)); - memcpy(bytes + VHD_OFFSET_RESERVED, vhd->reserved, sizeof(vhd->reserved)); -} - - -void -new_vhd_footer(vhd_footer_t **vhd) -{ - uint8_t cookie[8] = {'c', 'o', 'n', 'e', 'c', 't', 'i', 'x'}; - uint8_t creator[4] = {'8', '6', 'b', 'x'}; - uint8_t cr_host_os[4] = {'W', 'i', '2', 'k'}; - - if (*vhd == NULL) - *vhd = (vhd_footer_t *) malloc(sizeof(vhd_footer_t)); - - memcpy((*vhd)->cookie, cookie, 8); - (*vhd)->features = 0x00000002; - (*vhd)->version = 0x00010000; - (*vhd)->offset = 0xffffffffffffffff; /* fixed disk */ - (*vhd)->timestamp = calc_vhd_timestamp(); - memcpy((*vhd)->creator, creator, 4); - (*vhd)->creator_vers = 0x00010000; - memcpy((*vhd)->creator_host_os, cr_host_os, 4); - (*vhd)->type = 2; /* fixed disk */ - mk_guid((*vhd)->uuid); - (*vhd)->saved_state = 0; - memset((*vhd)->reserved, 0, 427); -} - - -void -generate_vhd_checksum(vhd_footer_t *vhd) -{ - uint32_t chk = 0; - int i; - for (i = 0; i < sizeof(vhd_footer_t); i++) { - /* We don't include the checksum field in the checksum */ - if ((i < VHD_OFFSET_CHECKSUM) || (i >= VHD_OFFSET_UUID)) - chk += ((uint8_t*)vhd)[i]; - } - vhd->checksum = ~chk; -} - - void hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size) { @@ -510,26 +245,6 @@ hdd_image_init(void) memset(&hdd_images[i], 0, sizeof(hdd_image_t)); } - -static void -hdd_image_gen_vft(int id, vhd_footer_t **vft, uint64_t full_size) -{ - /* Generate new footer. */ - new_vhd_footer(vft); - (*vft)->orig_size = (*vft)->curr_size = full_size; - (*vft)->geom.cyl = hdd[id].tracks; - (*vft)->geom.heads = hdd[id].hpc; - (*vft)->geom.spt = hdd[id].spt; - generate_vhd_checksum(*vft); - vhd_footer_to_bytes((uint8_t *) empty_sector, *vft); - fseeko64(hdd_images[id].file, 0, SEEK_END); - fwrite(empty_sector, 1, 512, hdd_images[id].file); - free(*vft); - *vft = NULL; - hdd_images[id].type = 3; -} - - int hdd_image_load(int id) { @@ -542,8 +257,7 @@ hdd_image_load(int id) uint64_t s = 0; wchar_t *fn = hdd[id].fn; int is_hdx[2] = { 0, 0 }; - int is_vhd[2] = { 0, 0 }; - vhd_footer_t *vft = NULL; + int is_vhd[2] = { 0, 0 }; memset(empty_sector, 0, sizeof(empty_sector)); @@ -633,7 +347,7 @@ hdd_image_load(int id) if (is_vhd[0]) { /* VHD image. */ - hdd_image_gen_vft(id, &vft, full_size); + hdd_images[id].type = 3; } return ret; @@ -704,29 +418,11 @@ hdd_image_load(int id) hdd[id].hpc = hpc; hdd[id].tracks = tracks; hdd_images[id].type = 2; - } else if (is_vhd[1]) { - if (fseeko64(hdd_images[id].file, -512, SEEK_END) == -1) - fatal("hdd_image_load(): VHD: Error seeking to 512 bytes before the end of file\n"); - if (fread(empty_sector, 1, 512, hdd_images[id].file) != 512) - fatal("hdd_image_load(): HDX: Error reading the footer\n"); - new_vhd_footer(&vft); - vhd_footer_from_bytes(vft, (uint8_t *) empty_sector); - if (vft->type != 2) { - /* VHD is not fixed size */ - hdd_image_log("VHD: Image is not fixed size\n"); - free(vft); - vft = NULL; - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - full_size = vft->orig_size; - hdd[id].tracks = vft->geom.cyl; - hdd[id].hpc = vft->geom.heads; - hdd[id].spt = vft->geom.spt; - free(vft); - vft = NULL; + } else if (is_vhd[1]) { + // full_size = VHD size in bytes + // hdd[id].tracks = VHD cylinders + // hdd[id].hpc = VHD heads + // hdd[id].spt = VHD spt hdd_images[id].type = 3; /* If we're here, this means there is a valid VHD footer in the image, which means that by definition, all valid sectors @@ -751,17 +447,7 @@ hdd_image_load(int id) hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; hdd_images[id].loaded = 1; ret = 1; - } - - if (is_vhd[0]) { - if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1) - fatal("hdd_image_load(): VHD: Error seeking to the end of file\n"); - s = ftello64(hdd_images[id].file); - if (s == (full_size + hdd_images[id].base)) { - /* VHD image. */ - hdd_image_gen_vft(id, &vft, full_size); - } - } + } return ret; } diff --git a/src/include/86box/hdd.h b/src/include/86box/hdd.h index 4da0e190f..24a66eae2 100644 --- a/src/include/86box/hdd.h +++ b/src/include/86box/hdd.h @@ -106,32 +106,6 @@ typedef struct { extern hard_disk_t hdd[HDD_NUM]; extern unsigned int hdd_table[128][3]; - -typedef struct vhd_footer_t -{ - uint8_t cookie[8]; - uint32_t features; - uint32_t version; - uint64_t offset; - uint32_t timestamp; - uint8_t creator[4]; - uint32_t creator_vers; - uint8_t creator_host_os[4]; - uint64_t orig_size; - uint64_t curr_size; - struct { - uint16_t cyl; - uint8_t heads; - uint8_t spt; - } geom; - uint32_t type; - uint32_t checksum; - uint8_t uuid[16]; - uint8_t saved_state; - uint8_t reserved[427]; -} vhd_footer_t; - - extern int hdd_init(void); extern int hdd_string_to_bus(char *str, int cdrom); extern char *hdd_bus_to_string(int bus, int cdrom); @@ -153,11 +127,6 @@ extern void hdd_image_unload(uint8_t id, int fn_preserve); extern void hdd_image_close(uint8_t id); extern void hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size); -extern void vhd_footer_from_bytes(vhd_footer_t *vhd, uint8_t *bytes); -extern void vhd_footer_to_bytes(uint8_t *bytes, vhd_footer_t *vhd); -extern void new_vhd_footer(vhd_footer_t **vhd); -extern void generate_vhd_checksum(vhd_footer_t *vhd); - extern int image_is_hdi(const wchar_t *s); extern int image_is_hdx(const wchar_t *s, int check_signature); extern int image_is_vhd(const wchar_t *s, int check_signature); diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 491ae7970..17cf4acf8 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -2401,12 +2401,11 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM uint32_t zero = 0, base = 0x1000; uint64_t signature = 0xD778A82044445459ll; uint64_t temp_size, r = 0; - char buf[512], *big_buf; + char *big_buf; int b = 0; uint8_t channel = 0; uint8_t id = 0; - wchar_t *twcs; - vhd_footer_t *vft = NULL; + wchar_t *twcs; MSG msg; switch (message) { @@ -2584,18 +2583,8 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM } if (image_is_vhd(hd_file_name, 0)) { - /* VHD image. */ - /* Generate new footer. */ - new_vhd_footer(&vft); - vft->orig_size = vft->curr_size = temp_size; - vft->geom.cyl = tracks; - vft->geom.heads = hpc; - vft->geom.spt = spt; - generate_vhd_checksum(vft); - vhd_footer_to_bytes((uint8_t *) big_buf, vft); - fwrite(big_buf, 1, 512, f); - free(vft); - vft = NULL; + /* VHD image. */ + // Create VHD image here of size temp_size bytes. } free(big_buf); @@ -2656,16 +2645,7 @@ hdd_add_file_open_error: fread(&hpc, 1, 4, f); fread(&tracks, 1, 4, f); } else if (image_is_vhd(wopenfilestring, 1)) { - fseeko64(f, -512, SEEK_END); - fread(buf, 1, 512, f); - new_vhd_footer(&vft); - vhd_footer_from_bytes(vft, (uint8_t *) buf); - size = vft->orig_size; - tracks = vft->geom.cyl; - hpc = vft->geom.heads; - spt = vft->geom.spt; - free(vft); - vft = NULL; + // Read VHD geometry } else { fseeko64(f, 0, SEEK_END); size = ftello64(f); From d91056586e03100698ff15d89ca4b56a49fca804 Mon Sep 17 00:00:00 2001 From: Stephen McKinney Date: Tue, 17 Nov 2020 23:31:38 -0600 Subject: [PATCH 03/67] Add VHD support. --- src/config.c | 5 + src/disk/hdd_image.c | 635 +++++++++++++++++++---------------- src/include/86box/language.h | 8 +- src/include/86box/resource.h | 4 + src/include/86box/win.h | 11 +- src/win/86Box.rc | 18 +- src/win/win_devconf.c | 2 +- src/win/win_dialog.c | 35 +- src/win/win_media_menu.c | 10 +- src/win/win_new_floppy.c | 2 +- src/win/win_settings.c | 365 ++++++++++++++++++-- 11 files changed, 763 insertions(+), 332 deletions(-) diff --git a/src/config.c b/src/config.c index 292c461d1..37de7b7b2 100644 --- a/src/config.c +++ b/src/config.c @@ -981,6 +981,11 @@ load_hard_disks(void) * files. We should remove this before * finalizing this release! --FvK */ + /* + * ANOTHER NOTE: + * When loading differencing VHDs, the absolute path is required. + * So we should not convert absolute paths to relative. -sards + */ if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { /* * Yep, its absolute and prefixed diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index 621e2f86c..fda699970 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -32,14 +32,21 @@ #include <86box/plat.h> #include <86box/random.h> #include <86box/hdd.h> +#include "minivhd/minivhd.h" +#include "minivhd/minivhd_internal.h" +#define HDD_IMAGE_RAW 0 +#define HDD_IMAGE_HDI 1 +#define HDD_IMAGE_HDX 2 +#define HDD_IMAGE_VHD 3 typedef struct { - FILE *file; + FILE *file; /* Used for HDD_IMAGE_RAW, HDD_IMAGE_HDI, and HDD_IMAGE_HDX. */ + MVHDMeta* vhd; /* Used for HDD_IMAGE_VHD. */ uint32_t base; uint32_t pos, last_sector; - uint8_t type; + uint8_t type; /* HDD_IMAGE_RAW, HDD_IMAGE_HDI, HDD_IMAGE_HDX, or HDD_IMAGE_VHD */ uint8_t loaded; } hdd_image_t; @@ -59,16 +66,15 @@ hdd_image_log(const char *fmt, ...) va_list ap; if (hdd_image_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else #define hdd_image_log(fmt, ...) #endif - int image_is_hdi(const wchar_t *s) { @@ -77,12 +83,12 @@ image_is_hdi(const wchar_t *s) char *ws = (char *) s; len = wcslen(s); if ((len < 4) || (s[0] == L'.')) - return 0; + return 0; memcpy(ext, ws + ((len - 4) << 1), 8); if (! wcscasecmp(ext, L".HDI")) - return 1; + return 1; else - return 0; + return 0; } @@ -97,34 +103,34 @@ image_is_hdx(const wchar_t *s, int check_signature) wchar_t ext[5] = { 0, 0, 0, 0, 0 }; len = wcslen(s); if ((len < 4) || (s[0] == L'.')) - return 0; + return 0; memcpy(ext, ws + ((len - 4) << 1), 8); if (wcscasecmp(ext, L".HDX") == 0) { - if (check_signature) { - f = plat_fopen((wchar_t *)s, L"rb"); - if (!f) - return 0; - if (fseeko64(f, 0, SEEK_END)) - fatal("image_is_hdx(): Error while seeking"); - filelen = ftello64(f); - if (fseeko64(f, 0, SEEK_SET)) - fatal("image_is_hdx(): Error while seeking"); - if (filelen < 44) { - if (f != NULL) - fclose(f); - return 0; - } - if (fread(&signature, 1, 8, f) != 8) - fatal("image_is_hdx(): Error reading signature\n"); - fclose(f); - if (signature == 0xD778A82044445459ll) - return 1; - else - return 0; - } else - return 1; + if (check_signature) { + f = plat_fopen((wchar_t *)s, L"rb"); + if (!f) + return 0; + if (fseeko64(f, 0, SEEK_END)) + fatal("image_is_hdx(): Error while seeking"); + filelen = ftello64(f); + if (fseeko64(f, 0, SEEK_SET)) + fatal("image_is_hdx(): Error while seeking"); + if (filelen < 44) { + if (f != NULL) + fclose(f); + return 0; + } + if (fread(&signature, 1, 8, f) != 8) + fatal("image_is_hdx(): Error reading signature\n"); + fclose(f); + if (signature == 0xD778A82044445459ll) + return 1; + else + return 0; + } else + return 1; } else - return 0; + return 0; } @@ -132,22 +138,26 @@ int image_is_vhd(const wchar_t *s, int check_signature) { int len; + FILE* f; char *ws = (char *) s; wchar_t ext[5] = { 0, 0, 0, 0, 0 }; len = wcslen(s); if ((len < 4) || (s[0] == L'.')) - return 0; + return 0; memcpy(ext, ws + ((len - 4) << 1), 8); if (wcscasecmp(ext, L".VHD") == 0) { - if (check_signature) { - // if is VHD - return 1; - // else - // return 0; - } else - return 1; + if (check_signature) { + f = plat_fopen((wchar_t*)s, L"rb"); + if (!f) + return 0; + + bool is_vhd = mvhd_file_is_vhd(f); + fclose(f); + return is_vhd ? 1 : 0; + } else + return 1; } else - return 0; + return 0; } void @@ -158,28 +168,28 @@ hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size) uint64_t ts = ((uint64_t) size) << 11LL; uint32_t spt, heads, cyl, cth; if (ts > 65535 * 16 * 255) - ts = 65535 * 16 * 255; + ts = 65535 * 16 * 255; if (ts >= 65535 * 16 * 63) { - spt = 255; - heads = 16; - cth = (uint32_t) (ts / spt); + spt = 255; + heads = 16; + cth = (uint32_t) (ts / spt); } else { - spt = 17; - cth = (uint32_t) (ts / spt); - heads = (cth +1023) / 1024; - if (heads < 4) - heads = 4; - if ((cth >= (heads * 1024)) || (heads > 16)) { - spt = 31; - heads = 16; - cth = (uint32_t) (ts / spt); - } - if (cth >= (heads * 1024)) { - spt = 63; - heads = 16; - cth = (uint32_t) (ts / spt); - } + spt = 17; + cth = (uint32_t) (ts / spt); + heads = (cth +1023) / 1024; + if (heads < 4) + heads = 4; + if ((cth >= (heads * 1024)) || (heads > 16)) { + spt = 31; + heads = 16; + cth = (uint32_t) (ts / spt); + } + if (cth >= (heads * 1024)) { + spt = 63; + heads = 16; + cth = (uint32_t) (ts / spt); + } } cyl = cth / heads; *c = cyl; @@ -209,18 +219,18 @@ prepare_new_hard_disk(uint8_t id, uint64_t full_size) /* First, write all the 1 MB blocks. */ if (t > 0) { - for (i = 0; i < t; i++) { - fseek(hdd_images[id].file, 0, SEEK_END); - fwrite(empty_sector_1mb, 1, 1048576, hdd_images[id].file); - pclog("#"); - } + for (i = 0; i < t; i++) { + fseek(hdd_images[id].file, 0, SEEK_END); + fwrite(empty_sector_1mb, 1, 1048576, hdd_images[id].file); + pclog("#"); + } } /* Then, write the remainder. */ if (size > 0) { - fseek(hdd_images[id].file, 0, SEEK_END); - fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); - pclog("#"); + fseek(hdd_images[id].file, 0, SEEK_END); + fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); + pclog("#"); } pclog("]\n"); /* Switch the suppression of seen messages back on. */ @@ -242,7 +252,7 @@ hdd_image_init(void) int i; for (i = 0; i < HDD_NUM; i++) - memset(&hdd_images[i], 0, sizeof(hdd_image_t)); + memset(&hdd_images[i], 0, sizeof(hdd_image_t)); } int @@ -256,19 +266,25 @@ hdd_image_load(int id) int c, ret; uint64_t s = 0; wchar_t *fn = hdd[id].fn; + char fn_multibyte_buf[1200]; int is_hdx[2] = { 0, 0 }; - int is_vhd[2] = { 0, 0 }; + int is_vhd[2] = { 0, 0 }; + int vhd_error = 0; memset(empty_sector, 0, sizeof(empty_sector)); hdd_images[id].base = 0; if (hdd_images[id].loaded) { - if (hdd_images[id].file) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - } - hdd_images[id].loaded = 0; + if (hdd_images[id].file) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } + else if (hdd_images[id].vhd) { + mvhd_close(hdd_images[id].vhd); + hdd_images[id].vhd = NULL; + } + hdd_images[id].loaded = 0; } is_hdx[0] = image_is_hdx(fn, 0); @@ -281,172 +297,199 @@ hdd_image_load(int id) /* Try to open existing hard disk image */ if (fn[0] == '.') { - hdd_image_log("File name starts with .\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; + hdd_image_log("File name starts with .\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; } hdd_images[id].file = plat_fopen(fn, L"rb+"); if (hdd_images[id].file == NULL) { - /* Failed to open existing hard disk image */ - if (errno == ENOENT) { - /* Failed because it does not exist, - so try to create new file */ - if (hdd[id].wp) { - hdd_image_log("A write-protected image must exist\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + if (hdd[id].wp) { + hdd_image_log("A write-protected image must exist\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } - hdd_images[id].file = plat_fopen(fn, L"wb+"); - if (hdd_images[id].file == NULL) { - hdd_image_log("Unable to open image\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } else { - if (image_is_hdi(fn)) { - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; - hdd_images[id].base = 0x1000; - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); - fwrite(&full_size, 1, 4, hdd_images[id].file); - fwrite(§or_size, 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); - for (c = 0; c < 0x3f8; c++) - fwrite(&zero, 1, 4, hdd_images[id].file); - hdd_images[id].type = 1; - } else if (is_hdx[0]) { - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; - hdd_images[id].base = 0x28; - fwrite(&signature, 1, 8, hdd_images[id].file); - fwrite(&full_size, 1, 8, hdd_images[id].file); - fwrite(§or_size, 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - hdd_images[id].type = 2; - } - else - hdd_images[id].type = 0; - hdd_images[id].last_sector = 0; - } + hdd_images[id].file = plat_fopen(fn, L"wb+"); + if (hdd_images[id].file == NULL) { + hdd_image_log("Unable to open image\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } else { + if (image_is_hdi(fn)) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x1000; + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); + fwrite(&full_size, 1, 4, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + for (c = 0; c < 0x3f8; c++) + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = HDD_IMAGE_HDI; + } else if (is_hdx[0]) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x28; + fwrite(&signature, 1, 8, hdd_images[id].file); + fwrite(&full_size, 1, 8, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = HDD_IMAGE_HDX; + } else if (is_vhd[0]) { + fclose(hdd_images[id].file); + MVHDGeom geometry; + geometry.cyl = hdd[id].tracks; + geometry.heads = hdd[id].hpc; + geometry.spt = hdd[id].spt; + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; - s = full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; + wcstombs(fn_multibyte_buf, fn, sizeof fn_multibyte_buf); + hdd_images[id].vhd = mvhd_create_fixed(fn_multibyte_buf, geometry, &vhd_error, NULL); + if (hdd_images[id].vhd == NULL) + fatal("hdd_image_load(): VHD: Could not create VHD : %s\n", mvhd_strerr(vhd_error)); - ret = prepare_new_hard_disk(id, full_size); + hdd_images[id].type = HDD_IMAGE_VHD; + return 1; + } else { + hdd_images[id].type = HDD_IMAGE_RAW; + } + hdd_images[id].last_sector = 0; + } - if (is_vhd[0]) { - /* VHD image. */ - hdd_images[id].type = 3; - } + s = full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; - return ret; - } else { - /* Failed for another reason */ - hdd_image_log("Failed for another reason\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } + ret = prepare_new_hard_disk(id, full_size); + return ret; + } else { + /* Failed for another reason */ + hdd_image_log("Failed for another reason\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } } else { - if (image_is_hdi(fn)) { - if (fseeko64(hdd_images[id].file, 0x8, SEEK_SET) == -1) - fatal("hdd_image_load(): HDI: Error seeking to offset 0x8\n"); - if (fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading base offset\n"); - if (fseeko64(hdd_images[id].file, 0xC, SEEK_SET) == -1) - fatal("hdd_image_load(): HDI: Error seeking to offest 0xC\n"); - full_size = 0LL; - if (fread(&full_size, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading full size\n"); - if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) - fatal("hdd_image_load(): HDI: Error seeking to offset 0x10\n"); - if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading sector size\n"); - if (sector_size != 512) { - /* Sector size is not 512 */ - hdd_image_log("HDI: Sector size is not 512\n"); - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - if (fread(&spt, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); - if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); - if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading number of tracks\n"); - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; - hdd_images[id].type = 1; - } else if (is_hdx[1]) { - hdd_images[id].base = 0x28; - if (fseeko64(hdd_images[id].file, 8, SEEK_SET) == -1) - fatal("hdd_image_load(): HDX: Error seeking to offset 0x8\n"); - if (fread(&full_size, 1, 8, hdd_images[id].file) != 8) - fatal("hdd_image_load(): HDX: Error reading full size\n"); - if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) - fatal("hdd_image_load(): HDX: Error seeking to offset 0x10\n"); - if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDX: Error reading sector size\n"); - if (sector_size != 512) { - /* Sector size is not 512 */ - hdd_image_log("HDX: Sector size is not 512\n"); - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - if (fread(&spt, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); - if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); - if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDX: Error reading number of tracks\n"); - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; - hdd_images[id].type = 2; - } else if (is_vhd[1]) { - // full_size = VHD size in bytes - // hdd[id].tracks = VHD cylinders - // hdd[id].hpc = VHD heads - // hdd[id].spt = VHD spt - hdd_images[id].type = 3; - /* If we're here, this means there is a valid VHD footer in the - image, which means that by definition, all valid sectors - are there. */ - hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; - hdd_images[id].loaded = 1; - return 1; - } else { - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; - hdd_images[id].type = 0; - } + if (image_is_hdi(fn)) { + if (fseeko64(hdd_images[id].file, 0x8, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offset 0x8\n"); + if (fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading base offset\n"); + if (fseeko64(hdd_images[id].file, 0xC, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offest 0xC\n"); + full_size = 0LL; + if (fread(&full_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading full size\n"); + if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offset 0x10\n"); + if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sector size\n"); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDI: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + if (fread(&spt, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); + if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); + if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading number of tracks\n"); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + hdd_images[id].type = HDD_IMAGE_HDI; + } else if (is_hdx[1]) { + hdd_images[id].base = 0x28; + if (fseeko64(hdd_images[id].file, 8, SEEK_SET) == -1) + fatal("hdd_image_load(): HDX: Error seeking to offset 0x8\n"); + if (fread(&full_size, 1, 8, hdd_images[id].file) != 8) + fatal("hdd_image_load(): HDX: Error reading full size\n"); + if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) + fatal("hdd_image_load(): HDX: Error seeking to offset 0x10\n"); + if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDX: Error reading sector size\n"); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDX: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + if (fread(&spt, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); + if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); + if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDX: Error reading number of tracks\n"); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + hdd_images[id].type = HDD_IMAGE_HDX; + } else if (is_vhd[1]) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + wcstombs(fn_multibyte_buf, fn, sizeof fn_multibyte_buf); + hdd_images[id].vhd = mvhd_open(fn_multibyte_buf, (bool)0, &vhd_error); + if (hdd_images[id].vhd == NULL) + { + if (vhd_error == MVHD_ERR_FILE) + fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn_multibyte_buf, strerror(mvhd_errno)); + else + fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn_multibyte_buf, mvhd_strerr(vhd_error)); + } + else if (vhd_error == MVHD_ERR_TIMESTAMP) + { + fatal("hdd_image_load(): VHD: Parent/child timestamp mismatch for VHD file '%s'\n", fn_multibyte_buf); + } + + full_size = hdd_images[id].vhd->footer.curr_sz; + hdd[id].tracks = hdd_images[id].vhd->footer.geom.cyl; + hdd[id].hpc = hdd_images[id].vhd->footer.geom.heads; + hdd[id].spt = hdd_images[id].vhd->footer.geom.spt; + hdd_images[id].type = HDD_IMAGE_VHD; + /* If we're here, this means there is a valid VHD footer in the + image, which means that by definition, all valid sectors + are there. */ + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + hdd_images[id].loaded = 1; + return 1; + } else { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].type = HDD_IMAGE_RAW; + } } if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1) - fatal("hdd_image_load(): Error seeking to the end of file\n"); + fatal("hdd_image_load(): Error seeking to the end of file\n"); s = ftello64(hdd_images[id].file); if (s < (full_size + hdd_images[id].base)) - ret = prepare_new_hard_disk(id, full_size); + ret = prepare_new_hard_disk(id, full_size); else { - hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; - hdd_images[id].loaded = 1; - ret = 1; + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + hdd_images[id].loaded = 1; + ret = 1; } return ret; @@ -460,36 +503,47 @@ hdd_image_seek(uint8_t id, uint32_t sector) addr = (uint64_t)sector << 9LL; hdd_images[id].pos = sector; - if (fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET) == -1) - fatal("hdd_image_seek(): Error seeking\n"); + if (hdd_images[id].type != HDD_IMAGE_VHD) { + if (fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET) == -1) + fatal("hdd_image_seek(): Error seeking\n"); + } } void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - int i; + if (hdd_images[id].type == HDD_IMAGE_VHD) { + int non_transferred_sectors = mvhd_read_sectors(hdd_images[id].vhd, sector, count, buffer); + hdd_images[id].pos = sector + count - non_transferred_sectors - 1; + } else { + int i; - if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { - fatal("Hard disk image %i: Read error during seek\n", id); - return; - } + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Read error during seek\n", id); + return; + } - for (i = 0; i < count; i++) { - if (feof(hdd_images[id].file)) - break; + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; - hdd_images[id].pos = sector + i; - fread(buffer + (i << 9), 1, 512, hdd_images[id].file); - } + hdd_images[id].pos = sector + i; + fread(buffer + (i << 9), 1, 512, hdd_images[id].file); + } + } } uint32_t hdd_sectors(uint8_t id) { - fseeko64(hdd_images[id].file, 0, SEEK_END); - return (uint32_t) ((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9); + if (hdd_images[id].type == HDD_IMAGE_VHD) { + return (uint32_t) (hdd_images[id].vhd->footer.curr_sz >> 9); + } else { + fseeko64(hdd_images[id].file, 0, SEEK_END); + return (uint32_t)((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9); + } } @@ -500,12 +554,12 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) uint32_t sectors = hdd_sectors(id); if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; + transfer_sectors = sectors - sector; hdd_image_read(id, sector, transfer_sectors, buffer); if (count != transfer_sectors) - return 1; + return 1; return 0; } @@ -513,20 +567,25 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - int i; + if (hdd_images[id].type == HDD_IMAGE_VHD) { + int non_transferred_sectors = mvhd_write_sectors(hdd_images[id].vhd, sector, count, buffer); + hdd_images[id].pos = sector + count - non_transferred_sectors - 1; + } else { + int i; - if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { - fatal("Hard disk image %i: Write error during seek\n", id); - return; - } + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Write error during seek\n", id); + return; + } - for (i = 0; i < count; i++) { - if (feof(hdd_images[id].file)) - break; + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; - hdd_images[id].pos = sector + i; - fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file); - } + hdd_images[id].pos = sector + i; + fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file); + } + } } @@ -537,12 +596,12 @@ hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) uint32_t sectors = hdd_sectors(id); if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; + transfer_sectors = sectors - sector; hdd_image_write(id, sector, transfer_sectors, buffer); if (count != transfer_sectors) - return 1; + return 1; return 0; } @@ -550,22 +609,27 @@ hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) { - uint32_t i = 0; + if (hdd_images[id].type == HDD_IMAGE_VHD) { + int non_transferred_sectors = mvhd_format_sectors(hdd_images[id].vhd, sector, count); + hdd_images[id].pos = sector + count - non_transferred_sectors - 1; + } else { + uint32_t i = 0; - memset(empty_sector, 0, 512); + memset(empty_sector, 0, 512); - if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { - fatal("Hard disk image %i: Zero error during seek\n", id); - return; - } + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Zero error during seek\n", id); + return; + } - for (i = 0; i < count; i++) { - if (feof(hdd_images[id].file)) - break; + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; - hdd_images[id].pos = sector + i; - fwrite(empty_sector, 512, 1, hdd_images[id].file); - } + hdd_images[id].pos = sector + i; + fwrite(empty_sector, 512, 1, hdd_images[id].file); + } + } } @@ -576,12 +640,12 @@ hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) uint32_t sectors = hdd_sectors(id); if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; + transfer_sectors = sectors - sector; hdd_image_zero(id, sector, transfer_sectors); if (count != transfer_sectors) - return 1; + return 1; return 0; } @@ -611,21 +675,24 @@ void hdd_image_unload(uint8_t id, int fn_preserve) { if (wcslen(hdd[id].fn) == 0) - return; + return; if (hdd_images[id].loaded) { - if (hdd_images[id].file != NULL) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - } - hdd_images[id].loaded = 0; + if (hdd_images[id].file != NULL) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } else if (hdd_images[id].vhd != NULL) { + mvhd_close(hdd_images[id].vhd); + hdd_images[id].vhd = NULL; + } + hdd_images[id].loaded = 0; } hdd_images[id].last_sector = -1; memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); if (fn_preserve) - wcscpy(hdd[id].prev_fn, hdd[id].fn); + wcscpy(hdd[id].prev_fn, hdd[id].fn); memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); } @@ -636,12 +703,16 @@ hdd_image_close(uint8_t id) hdd_image_log("hdd_image_close(%i)\n", id); if (!hdd_images[id].loaded) - return; + return; if (hdd_images[id].file != NULL) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } else if (hdd_images[id].vhd != NULL) { + mvhd_close(hdd_images[id].vhd); + hdd_images[id].vhd = NULL; } + memset(&hdd_images[id], 0, sizeof(hdd_image_t)); hdd_images[id].loaded = 0; } diff --git a/src/include/86box/language.h b/src/include/86box/language.h index a16f2f0ac..c4a4b64a5 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -140,6 +140,12 @@ #define IDS_4119 4119 // "Unsupported disk image" #define IDS_4120 4120 // "Overwrite" #define IDS_4121 4121 // "Don't Overwrite" +#define IDS_4122 4122 // "Raw image (.img)" +#define IDS_4123 4123 // "HDI image (.hdi)" +#define IDS_4124 4124 // "HDX image (.hdx)" +#define IDS_4125 4125 // "Fixed-size VHD (.vhd)" +#define IDS_4126 4126 // "Dynamic-size VHD (.vhd)" +#define IDS_4127 4127 // "Differencing VHD (.vhd)" #define IDS_4352 4352 // "MFM/RLL" #define IDS_4353 4353 // "XT IDE" @@ -209,7 +215,7 @@ #define STR_NUM_2048 92 #define STR_NUM_3072 11 -#define STR_NUM_4096 18 +#define STR_NUM_4096 32 #define STR_NUM_4352 6 #define STR_NUM_4608 6 #define STR_NUM_5120 1 diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index b0422d18b..b0e194bb8 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -105,6 +105,8 @@ #define IDT_1771 1771 /* ID: */ #define IDT_1772 1772 /* Channel */ #define IDT_1773 1773 /* Type: */ +#define IDT_1774 1774 /* Image Format: */ +#define IDT_1775 1775 /* Block Size: */ /* @@ -218,6 +220,8 @@ #define IDC_EDIT_HD_SIZE 1164 #define IDC_COMBO_HD_TYPE 1165 #define IDC_PBAR_IMG_CREATE 1166 +#define IDC_COMBO_HD_IMG_FORMAT 1167 +#define IDC_COMBO_HD_BLOCK_SIZE 1168 #define IDC_REMOV_DEVICES 1170 /* floppy and cd-rom drives config */ #define IDC_LIST_FLOPPY_DRIVES 1171 diff --git a/src/include/86box/win.h b/src/include/86box/win.h index a181dad06..aae82adac 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -193,11 +193,12 @@ extern int MediaMenuHandler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPara /* Functions in win_dialog.c: */ -extern int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save); -extern int file_dlg(HWND hwnd, WCHAR *f, char *fn, int save); -extern int file_dlg_mb(HWND hwnd, char *f, char *fn, int save); -extern int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, int save); -extern int file_dlg_st(HWND hwnd, int i, char *fn, int save); +/* Pass NULL in the title param to use the default title. */ +extern int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, WCHAR *title, int save); +extern int file_dlg(HWND hwnd, WCHAR *f, char *fn, char *title, int save); +extern int file_dlg_mb(HWND hwnd, char *f, char *fn, char *title, int save); +extern int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, char *title, int save); +extern int file_dlg_st(HWND hwnd, int i, char *fn, char *title, int save); extern wchar_t *BrowseFolder(wchar_t *saved_path, wchar_t *title); diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 7216bc391..873cb9e1f 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -575,13 +575,13 @@ BEGIN WS_VSCROLL | WS_TABSTOP END -DLG_CFG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 219, 111 +DLG_CFG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 219, 149 STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Add Hard Disk" FONT 9, "Segoe UI" BEGIN - DEFPUSHBUTTON "OK",IDOK,55,89,50,14 - PUSHBUTTON "Cancel",IDCANCEL,112,89,50,14 + DEFPUSHBUTTON "OK",IDOK,55,127,50,14 + PUSHBUTTON "Cancel",IDCANCEL,112,127,50,14 EDITTEXT IDC_EDIT_HD_FILE_NAME,7,16,153,12 PUSHBUTTON "&Specify...",IDC_CFILE,167,16,44,12 EDITTEXT IDC_EDIT_HD_SPT,183,34,28,12 @@ -607,6 +607,12 @@ BEGIN LTEXT "ID:",IDT_1723,99,73,34,8 COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,134,71,77,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Image Format:",IDT_1774,7,92,50,12 + COMBOBOX IDC_COMBO_HD_IMG_FORMAT,58,90,153,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Block Size:",IDT_1775,7,111,50,12 + COMBOBOX IDC_COMBO_HD_BLOCK_SIZE,58,109,153,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP LTEXT "Progress:",IDT_1752,7,7,204,9 CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | WS_BORDER,7,16,204,12 @@ -1055,6 +1061,12 @@ BEGIN IDS_4119 "Unsupported disk image" IDS_4120 "Overwrite" IDS_4121 "Don't Overwrite" + IDS_4122 "Raw image (.img)" + IDS_4123 "HDI image (.hdi)" + IDS_4124 "HDX image (.hdx)" + IDS_4125 "Fixed-size VHD (.vhd)" + IDS_4126 "Dynamic-size VHD (.vhd)" + IDS_4127 "Differencing VHD (.vhd)" IDS_4352 "MFM/RLL" IDS_4353 "XTA" diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index 280dce484..18b567d79 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -412,7 +412,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) ws[c] = 0; } - if (!file_dlg(hdlg, ws, s, 0)) + if (!file_dlg(hdlg, ws, s, NULL, 0)) SendMessage(h, WM_SETTEXT, 0, (LPARAM)wopenfilestring); } break; diff --git a/src/win/win_dialog.c b/src/win/win_dialog.c index 563920cc3..16b1a2cc3 100644 --- a/src/win/win_dialog.c +++ b/src/win/win_dialog.c @@ -152,7 +152,7 @@ ui_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn2, voi int -file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) +file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, WCHAR *title, int save) { OPENFILENAME ofn; BOOL r; @@ -177,7 +177,9 @@ file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_PATHMUSTEXIST; if (! save) - ofn.Flags |= OFN_FILEMUSTEXIST; + ofn.Flags |= OFN_FILEMUSTEXIST; + if (title) + ofn.lpstrTitle = title; /* Display the Open dialog box. */ if (save) @@ -199,37 +201,44 @@ file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) int -file_dlg(HWND hwnd, WCHAR *f, char *fn, int save) +file_dlg(HWND hwnd, WCHAR *f, char *fn, char *title, int save) { - WCHAR ufn[512]; + WCHAR ufn[512], title_buf[512]; mbstowcs(ufn, fn, strlen(fn) + 1); + if (title) + mbstowcs(title_buf, title, sizeof title_buf); - return(file_dlg_w(hwnd, f, ufn, save)); + return(file_dlg_w(hwnd, f, ufn, title ? title_buf : NULL, save)); } int -file_dlg_mb(HWND hwnd, char *f, char *fn, int save) +file_dlg_mb(HWND hwnd, char *f, char *fn, char *title, int save) { - WCHAR uf[512], ufn[512]; + WCHAR uf[512], ufn[512], title_buf[512]; mbstowcs(uf, f, strlen(fn) + 1); mbstowcs(ufn, fn, strlen(fn) + 1); + if (title) + mbstowcs(title_buf, title, sizeof title_buf); - return(file_dlg_w(hwnd, uf, ufn, save)); + return(file_dlg_w(hwnd, uf, ufn, title ? title_buf : NULL, save)); } int -file_dlg_w_st(HWND hwnd, int id, WCHAR *fn, int save) +file_dlg_w_st(HWND hwnd, int id, WCHAR *fn, char *title, int save) { - return(file_dlg_w(hwnd, plat_get_string(id), fn, save)); + WCHAR title_buf[512]; + if (title) + mbstowcs(title_buf, title, sizeof title_buf); + return(file_dlg_w(hwnd, plat_get_string(id), fn, title ? title_buf : NULL, save)); } int -file_dlg_st(HWND hwnd, int id, char *fn, int save) -{ - return(file_dlg(hwnd, plat_get_string(id), fn, save)); +file_dlg_st(HWND hwnd, int id, char *fn, char *title, int save) +{ + return(file_dlg(hwnd, plat_get_string(id), fn, title, save)); } diff --git a/src/win/win_media_menu.c b/src/win/win_media_menu.c index 45963c15a..d7e6b6cba 100644 --- a/src/win/win_media_menu.c +++ b/src/win/win_media_menu.c @@ -413,7 +413,7 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) wp = 1; /* FALLTHROUGH */ case IDM_FLOPPY_IMAGE_EXISTING: - ret = file_dlg_w_st(hwnd, IDS_2109, floppyfns[id], 0); + ret = file_dlg_w_st(hwnd, IDS_2109, floppyfns[id], NULL, 0); if (! ret) { floppy_mount(id, wopenfilestring, wp); } @@ -424,7 +424,7 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_FLOPPY_EXPORT_TO_86F: - ret = file_dlg_w_st(hwnd, IDS_2076, floppyfns[id], 1); + ret = file_dlg_w_st(hwnd, IDS_2076, floppyfns[id], NULL, 1); if (! ret) { plat_pause(1); ret = d86f_export(id, wopenfilestring); @@ -450,7 +450,7 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_CDROM_IMAGE: - if (!file_dlg_w_st(hwnd, IDS_2075, cdrom[id].image_path, 0)) { + if (!file_dlg_w_st(hwnd, IDS_2075, cdrom[id].image_path, NULL, 0)) { cdrom_mount(id, wopenfilestring); } break; @@ -463,7 +463,7 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) wp = 1; /* FALLTHROUGH */ case IDM_ZIP_IMAGE_EXISTING: - ret = file_dlg_w_st(hwnd, IDS_2058, zip_drives[id].image_path, 0); + ret = file_dlg_w_st(hwnd, IDS_2058, zip_drives[id].image_path, NULL, 0); if (! ret) zip_mount(id, wopenfilestring, wp); break; @@ -484,7 +484,7 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) wp = 1; /* FALLTHROUGH */ case IDM_MO_IMAGE_EXISTING: - ret = file_dlg_w_st(hwnd, IDS_2116, mo_drives[id].image_path, 0); + ret = file_dlg_w_st(hwnd, IDS_2116, mo_drives[id].image_path, NULL, 0); if (! ret) mo_mount(id, wopenfilestring, wp); break; diff --git a/src/win/win_new_floppy.c b/src/win/win_new_floppy.c index 9845c77cf..090bb9df4 100644 --- a/src/win/win_new_floppy.c +++ b/src/win/win_new_floppy.c @@ -777,7 +777,7 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return TRUE; case IDC_CFILE: - if (!file_dlg_w(hdlg, plat_get_string(is_mo ? IDS_2139 : (is_zip ? IDS_2055 : IDS_2062)), L"", 1)) { + if (!file_dlg_w(hdlg, plat_get_string(is_mo ? IDS_2139 : (is_zip ? IDS_2055 : IDS_2062)), L"", NULL, 1)) { if (!wcschr(wopenfilestring, L'.')) { if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { twcs = &wopenfilestring[wcslen(wopenfilestring)]; diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 17cf4acf8..a23690b1d 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -64,6 +64,8 @@ #include <86box/plat_midi.h> #include <86box/ui.h> #include <86box/win.h> +#include "../disk/minivhd/minivhd.h" +#include "../disk/minivhd/minivhd_util.h" /* Icon, Bus, File, C, H, S, Size */ @@ -2344,6 +2346,17 @@ set_edit_box_contents(HWND hdlg, int id, uint32_t val) SendMessage(h, WM_SETTEXT, (WPARAM) wcslen(szText), (LPARAM) szText); } +static void set_edit_box_text_contents(HWND hdlg, int id, WCHAR* text) +{ + HWND h = GetDlgItem(hdlg, id); + SendMessage(h, WM_SETTEXT, (WPARAM) wcslen(text), (LPARAM) text); +} + +static void get_edit_box_text_contents(HWND hdlg, int id, WCHAR* text_buffer, int buffer_size) +{ + HWND h = GetDlgItem(hdlg, id); + SendMessage(h, WM_GETTEXT, (WPARAM) buffer_size, (LPARAM) text_buffer); +} static int hdconf_initialize_hdt_combo(HWND hdlg) { @@ -2387,6 +2400,161 @@ recalc_selection(HWND hdlg) settings_set_cur_sel(hdlg, IDC_COMBO_HD_TYPE, selection); } +HWND vhd_progress_hdlg; + +static void vhd_progress_callback(uint32_t current_sector, uint32_t total_sectors) +{ + MSG msg; + HWND h = GetDlgItem(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE); + SendMessage(h, PBM_SETPOS, (WPARAM) current_sector, (LPARAM) 0); + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +/* If the disk geometry requested in the 86Box GUI is not compatible with the internal VHD geometry, + * we adjust it to the next-largest size that is compatible. On average, this will be a difference + * of about 21 MB, and should only be necessary for VHDs larger than 31.5 GB, so should never be more + * than a tenth of a percent change in size. + */ +static void adjust_86box_geometry_for_vhd(MVHDGeom *_86box_geometry, MVHDGeom *vhd_geometry) +{ + if (_86box_geometry->cyl <= 65535) { + vhd_geometry->cyl = _86box_geometry->cyl; + vhd_geometry->heads = _86box_geometry->heads; + vhd_geometry->spt = _86box_geometry->spt; + return; + } + + int desired_sectors = _86box_geometry->cyl * _86box_geometry->heads * _86box_geometry->spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; + + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors += (85680 - remainder); + + _86box_geometry->cyl = desired_sectors / (16 * 63); + _86box_geometry->heads = 16; + _86box_geometry->spt = 63; + + vhd_geometry->cyl = desired_sectors / (16 * 255); + vhd_geometry->heads = 16; + vhd_geometry->spt = 255; +} + +static void adjust_vhd_geometry_for_86box(MVHDGeom *vhd_geometry) +{ + if (vhd_geometry->spt <= 63) + return; + + int desired_sectors = vhd_geometry->cyl * vhd_geometry->heads * vhd_geometry->spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; + + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors -= remainder; + + vhd_geometry->cyl = desired_sectors / (16 * 63); + vhd_geometry->heads = 16; + vhd_geometry->spt = 63; +} + +static MVHDGeom create_drive_vhd_fixed(char* filename, int cyl, int heads, int spt) +{ + MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom vhd_geometry; + adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); + + HWND h = GetDlgItem(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE); + settings_show_window(vhd_progress_hdlg, IDT_1731, FALSE); + settings_show_window(vhd_progress_hdlg, IDC_EDIT_HD_FILE_NAME, FALSE); + settings_show_window(vhd_progress_hdlg, IDC_CFILE, FALSE); + settings_show_window(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE, TRUE); + settings_enable_window(vhd_progress_hdlg, IDT_1752, TRUE); + SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) vhd_geometry.cyl * vhd_geometry.heads * vhd_geometry.spt); + SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); + + int vhd_error = 0; + MVHDMeta *vhd = mvhd_create_fixed(filename, vhd_geometry, &vhd_error, vhd_progress_callback); + if (vhd == NULL) + { + _86box_geometry.cyl = 0; + _86box_geometry.heads = 0; + _86box_geometry.spt = 0; + } + else + { + mvhd_close(vhd); + } + + return _86box_geometry; +} + +static MVHDGeom create_drive_vhd_dynamic(char* filename, int cyl, int heads, int spt, int blocksize) +{ + MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom vhd_geometry; + adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); + int vhd_error = 0; + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = filename; + options.size_in_bytes = 0; + options.geometry = vhd_geometry; + options.type = MVHD_TYPE_DYNAMIC; + + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + if (vhd == NULL) + { + _86box_geometry.cyl = 0; + _86box_geometry.heads = 0; + _86box_geometry.spt = 0; + } + else + { + mvhd_close(vhd); + } + + return _86box_geometry; +} + +static MVHDGeom create_drive_vhd_diff(char* filename, char* parent_filename, int blocksize) +{ + int vhd_error = 0; + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = filename; + options.parent_path = parent_filename; + options.type = MVHD_TYPE_DIFF; + + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + MVHDGeom vhd_geometry; + if (vhd == NULL) + { + vhd_geometry.cyl = 0; + vhd_geometry.heads = 0; + vhd_geometry.spt = 0; + } + else + { + vhd_geometry = mvhd_get_geometry(vhd); + + if (vhd_geometry.spt > 63) + { + vhd_geometry.cyl = mvhd_calc_size_sectors(&vhd_geometry) / (16 * 63); + vhd_geometry.heads = 16; + vhd_geometry.spt = 63; + } + + mvhd_close(vhd); + } + + return vhd_geometry; +} + #if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK @@ -2400,19 +2568,26 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM uint32_t temp, i = 0, sector_size = 512; uint32_t zero = 0, base = 0x1000; uint64_t signature = 0xD778A82044445459ll; - uint64_t temp_size, r = 0; + uint64_t r = 0; char *big_buf; + char hd_file_name_multibyte[1200]; int b = 0; + int vhd_error = 0; uint8_t channel = 0; uint8_t id = 0; wchar_t *twcs; MSG msg; + int img_format, block_size; + WCHAR text_buf[256]; + RECT rect; + POINT point; + int dlg_height_adjust; switch (message) { case WM_INITDIALOG: memset(hd_file_name, 0, sizeof(hd_file_name)); - hdd_ptr = &(temp_hdd[next_free_id]); + hdd_ptr = &(temp_hdd[next_free_id]); SetWindowText(hdlg, plat_get_string((existing & 1) ? IDS_4103 : IDS_4102)); @@ -2426,15 +2601,61 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM size = (tracks * hpc * spt) << 9; set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20LL)); hdconf_initialize_hdt_combo(hdlg); + + // TODO: Why is it crashing when I try to use string resources here? + // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4122)); + // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4123)); + // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4124)); + // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4125)); + // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4126)); + // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4127)); + + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Raw image (.img)"); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"HDI image (.hdi)"); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"HDX image (.hdx)"); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Fixed-size VHD (.vhd)"); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Dynamic-size VHD (.vhd)"); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Differencing VHD (.vhd)"); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT, 0); + + settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, (LPARAM) L"Large blocks (2 MB)"); + settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, (LPARAM) L"Small blocks (512 KB)"); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_BLOCK_SIZE, 0); + + settings_show_window(hdlg, IDC_COMBO_HD_BLOCK_SIZE, FALSE); + settings_show_window(hdlg, IDT_1775, FALSE); + if (existing & 1) { settings_enable_window(hdlg, IDC_EDIT_HD_SPT, FALSE); settings_enable_window(hdlg, IDC_EDIT_HD_HPC, FALSE); settings_enable_window(hdlg, IDC_EDIT_HD_CYL, FALSE); settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, FALSE); settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, FALSE); + settings_show_window(hdlg, IDC_COMBO_HD_IMG_FORMAT, FALSE); + settings_show_window(hdlg, IDT_1774, FALSE); + + /* adjust window size */ + GetWindowRect(hdlg, &rect); + OffsetRect(&rect, -rect.left, -rect.top); + dlg_height_adjust = rect.bottom / 5; + SetWindowPos(hdlg, NULL, 0, 0, rect.right, rect.bottom - dlg_height_adjust, SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOZORDER); + h = GetDlgItem(hdlg, IDOK); + GetWindowRect(h, &rect); + point.x = rect.left; + point.y = rect.top; + ScreenToClient(hdlg, &point); + SetWindowPos(h, NULL, point.x, point.y - dlg_height_adjust, 0, 0, SWP_NOSIZE | SWP_NOREPOSITION | SWP_NOZORDER); + h = GetDlgItem(hdlg, IDCANCEL); + GetWindowRect(h, &rect); + point.x = rect.left; + point.y = rect.top; + ScreenToClient(hdlg, &point); + SetWindowPos(h, NULL, point.x, point.y - dlg_height_adjust, 0, 0, SWP_NOSIZE | SWP_NOREPOSITION | SWP_NOZORDER); + chs_enabled = 0; } else chs_enabled = 1; + add_locations(hdlg); hdd_ptr->bus = HDD_BUS_IDE; max_spt = 63; @@ -2502,19 +2723,22 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM memset(hdd_ptr->fn, 0, sizeof(hdd_ptr->fn)); wcscpy(hdd_ptr->fn, hd_file_name); + wcstombs(hd_file_name_multibyte, hd_file_name, sizeof hd_file_name_multibyte); sector_size = 512; if (!(existing & 1) && (wcslen(hd_file_name) > 0)) { - f = _wfopen(hd_file_name, L"wb"); - - if (size > 0x1FFFFFFE00ll) { - fclose(f); + if (size > 0x1FFFFFFE00ll) { settings_msgbox_header(MBX_ERROR, (wchar_t *) IDS_4116, (wchar_t *) IDS_4105); return TRUE; } - if (image_is_hdi(hd_file_name)) { + img_format = settings_get_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT); + if (img_format < 3) { + f = _wfopen(hd_file_name, L"wb"); + } + + if (img_format == 1) { /* HDI file */ if (size >= 0x100000000ll) { fclose(f); settings_msgbox_header(MBX_ERROR, (wchar_t *) IDS_4116, (wchar_t *) IDS_4104); @@ -2532,7 +2756,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM for (i = 0; i < 0x3f8; i++) fwrite(&zero, 1, 4, f); - } else if (image_is_hdx(hd_file_name, 0)) { + } else if (img_format == 2) { /* HDX file */ fwrite(&signature, 1, 8, f); /* 00000000: Signature */ fwrite(&size, 1, 8, f); /* 00000008: Full size of the data (64-bit) */ fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ @@ -2541,12 +2765,39 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ fwrite(&zero, 1, 4, f); /* 00000020: [Translation] Sectors per cylinder */ fwrite(&zero, 1, 4, f); /* 00000004: [Translation] Heads per cylinder */ - } + } else if (img_format >= 3) { /* VHD file */ + MVHDGeom _86box_geometry; + block_size = settings_get_cur_sel(hdlg, IDC_COMBO_HD_BLOCK_SIZE) == 0 ? MVHD_BLOCK_LARGE : MVHD_BLOCK_SMALL; + switch (img_format) { + case 3: + vhd_progress_hdlg = hdlg; + _86box_geometry = create_drive_vhd_fixed(hd_file_name_multibyte, tracks, hpc, spt); + break; + case 4: + _86box_geometry = create_drive_vhd_dynamic(hd_file_name_multibyte, tracks, hpc, spt, block_size); + break; + case 5: + if (file_dlg_w(hdlg, L"VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0", L"", L"Select the parent VHD",0)) { + return TRUE; + } + _86box_geometry = create_drive_vhd_diff(hd_file_name_multibyte, openfilestring, block_size); + break; + } + + if (img_format != 5) + settings_msgbox_header(MBX_INFO, (wchar_t *) IDS_4113, (wchar_t *) IDS_4117); + + hdd_ptr->tracks = _86box_geometry.cyl; + hdd_ptr->hpc = _86box_geometry.heads; + hdd_ptr->spt = _86box_geometry.spt; + + hard_disk_added = 1; + EndDialog(hdlg, 0); + return TRUE; + } big_buf = (char *) malloc(1048576); - memset(big_buf, 0, 1048576); - - temp_size = size; + memset(big_buf, 0, 1048576); r = size >> 20; size &= 0xfffff; @@ -2580,12 +2831,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM DispatchMessage(&msg); } } - } - - if (image_is_vhd(hd_file_name, 0)) { - /* VHD image. */ - // Create VHD image here of size temp_size bytes. - } + } free(big_buf); @@ -2603,8 +2849,8 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM EndDialog(hdlg, 0); return TRUE; - case IDC_CFILE: - if (!file_dlg_w(hdlg, plat_get_string(IDS_4106), L"", !(existing & 1))) { + case IDC_CFILE: + if (!file_dlg_w(hdlg, plat_get_string(IDS_4106), L"", NULL, !(existing & 1))) { if (!wcschr(wopenfilestring, L'.')) { if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { twcs = &wopenfilestring[wcslen(wopenfilestring)]; @@ -2645,7 +2891,39 @@ hdd_add_file_open_error: fread(&hpc, 1, 4, f); fread(&tracks, 1, 4, f); } else if (image_is_vhd(wopenfilestring, 1)) { - // Read VHD geometry + fclose(f); + wcstombs(hd_file_name_multibyte, wopenfilestring, sizeof hd_file_name_multibyte); + MVHDMeta* vhd = mvhd_open(hd_file_name_multibyte, 0, &vhd_error); + if (vhd == NULL) { + settings_msgbox_header(MBX_ERROR, (existing & 1) ? (wchar_t *) IDS_4114 : (wchar_t *) IDS_4115, (existing & 1) ? (wchar_t *) IDS_4107 : (wchar_t *) IDS_4108); + return TRUE; + } else if (vhd_error == MVHD_ERR_TIMESTAMP) { + wchar_t* ts_warning = + L"WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH!\n\n" + "This could indicate that the parent image was modified after this VHD was created.\n\n" + "This could also happen if the VHD files were moved/copied, or the differencing VHD was created with DiskPart.\n\n" + "Do you wish to fix this error after a file copy or DiskPart creation?"; + if (settings_msgbox_ex(MBX_QUESTION_YN, L"VHD Timestamp Mismatch", ts_warning, NULL, NULL, NULL) != 0) { + int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhd_error); + if (ts_res != 0) + { + settings_msgbox_header(MBX_ERROR, L"Error", L"Could not fix VHD timestamp."); + mvhd_close(vhd); + return TRUE; + } + } else { + mvhd_close(vhd); + return TRUE; + } + } + + MVHDGeom vhd_geom = mvhd_get_geometry(vhd); + adjust_vhd_geometry_for_86box(&vhd_geom); + tracks = vhd_geom.cyl; + hpc = vhd_geom.heads; + spt = vhd_geom.spt; + size = (uint64_t)tracks * hpc * spt * 512; + mvhd_close(vhd); } else { fseeko64(f, 0, SEEK_END); size = ftello64(f); @@ -2951,6 +3229,51 @@ hdd_add_file_open_error: no_update = 0; break; + case IDC_COMBO_HD_IMG_FORMAT: + img_format = settings_get_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT); + + no_update = 1; + if (img_format == 5) { /* They switched to a diff VHD; disable the geometry fields. */ + settings_enable_window(hdlg, IDC_EDIT_HD_SPT, FALSE); + set_edit_box_text_contents(hdlg, IDC_EDIT_HD_SPT, L"(N/A)"); + settings_enable_window(hdlg, IDC_EDIT_HD_HPC, FALSE); + set_edit_box_text_contents(hdlg, IDC_EDIT_HD_HPC, L"(N/A)"); + settings_enable_window(hdlg, IDC_EDIT_HD_CYL, FALSE); + set_edit_box_text_contents(hdlg, IDC_EDIT_HD_CYL, L"(N/A)"); + settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, FALSE); + set_edit_box_text_contents(hdlg, IDC_EDIT_HD_SIZE, L"(N/A)"); + settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, FALSE); + settings_reset_content(hdlg, IDC_COMBO_HD_TYPE); + settings_add_string(hdlg, IDC_COMBO_HD_TYPE, (LPARAM) L"(use parent)"); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_TYPE, 0); + } else { + get_edit_box_text_contents(hdlg, IDC_EDIT_HD_SPT, text_buf, 256); + if (!wcscmp(text_buf, L"(N/A)")) { + settings_enable_window(hdlg, IDC_EDIT_HD_SPT, TRUE); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, 17); + settings_enable_window(hdlg, IDC_EDIT_HD_HPC, TRUE); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, 15); + settings_enable_window(hdlg, IDC_EDIT_HD_CYL, TRUE); + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, 1023); + settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, TRUE); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) ((uint64_t)17 * 15 * 1023 * 512 >> 20)); + settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, TRUE); + hdconf_initialize_hdt_combo(hdlg); + } + } + no_update = 0; + + if (img_format == 4 || img_format == 5) /* For dynamic and diff VHDs, show the block size dropdown. */ + { + settings_show_window(hdlg, IDC_COMBO_HD_BLOCK_SIZE, TRUE); + settings_show_window(hdlg, IDT_1775, TRUE); + } + else /* Hide it otherwise. */ + { + settings_show_window(hdlg, IDC_COMBO_HD_BLOCK_SIZE, FALSE); + settings_show_window(hdlg, IDT_1775, FALSE); + } + break; } return FALSE; From 617b44d54fa00d0454a703b6e85cc1e43e42e115 Mon Sep 17 00:00:00 2001 From: Stephen McKinney Date: Wed, 18 Nov 2020 21:10:33 -0600 Subject: [PATCH 04/67] Fix whitespace. --- src/disk/hdd_image.c | 964 +++++++++++++++++------------------ src/include/86box/language.h | 12 +- src/include/86box/resource.h | 18 +- src/win/win_settings.c | 290 +++++------ 4 files changed, 634 insertions(+), 650 deletions(-) diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index fda699970..d506734d5 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -42,12 +42,12 @@ typedef struct { - FILE *file; /* Used for HDD_IMAGE_RAW, HDD_IMAGE_HDI, and HDD_IMAGE_HDX. */ - MVHDMeta* vhd; /* Used for HDD_IMAGE_VHD. */ - uint32_t base; - uint32_t pos, last_sector; - uint8_t type; /* HDD_IMAGE_RAW, HDD_IMAGE_HDI, HDD_IMAGE_HDX, or HDD_IMAGE_VHD */ - uint8_t loaded; + FILE *file; /* Used for HDD_IMAGE_RAW, HDD_IMAGE_HDI, and HDD_IMAGE_HDX. */ + MVHDMeta* vhd; /* Used for HDD_IMAGE_VHD. */ + uint32_t base; + uint32_t pos, last_sector; + uint8_t type; /* HDD_IMAGE_RAW, HDD_IMAGE_HDI, HDD_IMAGE_HDX, or HDD_IMAGE_VHD */ + uint8_t loaded; } hdd_image_t; @@ -63,13 +63,13 @@ int hdd_image_do_log = ENABLE_HDD_IMAGE_LOG; static void hdd_image_log(const char *fmt, ...) { - va_list ap; + va_list ap; - if (hdd_image_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } + if (hdd_image_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } } #else #define hdd_image_log(fmt, ...) @@ -78,641 +78,639 @@ hdd_image_log(const char *fmt, ...) int image_is_hdi(const wchar_t *s) { - int len; - wchar_t ext[5] = { 0, 0, 0, 0, 0 }; - char *ws = (char *) s; - len = wcslen(s); - if ((len < 4) || (s[0] == L'.')) - return 0; - memcpy(ext, ws + ((len - 4) << 1), 8); - if (! wcscasecmp(ext, L".HDI")) - return 1; - else - return 0; + int len; + wchar_t ext[5] = { 0, 0, 0, 0, 0 }; + char *ws = (char *) s; + len = wcslen(s); + if ((len < 4) || (s[0] == L'.')) + return 0; + memcpy(ext, ws + ((len - 4) << 1), 8); + if (! wcscasecmp(ext, L".HDI")) + return 1; + else + return 0; } int image_is_hdx(const wchar_t *s, int check_signature) { - int len; - FILE *f; - uint64_t filelen; - uint64_t signature; - char *ws = (char *) s; - wchar_t ext[5] = { 0, 0, 0, 0, 0 }; - len = wcslen(s); - if ((len < 4) || (s[0] == L'.')) - return 0; - memcpy(ext, ws + ((len - 4) << 1), 8); - if (wcscasecmp(ext, L".HDX") == 0) { - if (check_signature) { - f = plat_fopen((wchar_t *)s, L"rb"); - if (!f) - return 0; - if (fseeko64(f, 0, SEEK_END)) - fatal("image_is_hdx(): Error while seeking"); - filelen = ftello64(f); - if (fseeko64(f, 0, SEEK_SET)) - fatal("image_is_hdx(): Error while seeking"); - if (filelen < 44) { - if (f != NULL) - fclose(f); - return 0; - } - if (fread(&signature, 1, 8, f) != 8) - fatal("image_is_hdx(): Error reading signature\n"); - fclose(f); - if (signature == 0xD778A82044445459ll) - return 1; - else - return 0; - } else - return 1; - } else - return 0; + int len; + FILE *f; + uint64_t filelen; + uint64_t signature; + char *ws = (char *) s; + wchar_t ext[5] = { 0, 0, 0, 0, 0 }; + len = wcslen(s); + if ((len < 4) || (s[0] == L'.')) + return 0; + memcpy(ext, ws + ((len - 4) << 1), 8); + if (wcscasecmp(ext, L".HDX") == 0) { + if (check_signature) { + f = plat_fopen((wchar_t *)s, L"rb"); + if (!f) + return 0; + if (fseeko64(f, 0, SEEK_END)) + fatal("image_is_hdx(): Error while seeking"); + filelen = ftello64(f); + if (fseeko64(f, 0, SEEK_SET)) + fatal("image_is_hdx(): Error while seeking"); + if (filelen < 44) { + if (f != NULL) + fclose(f); + return 0; + } + if (fread(&signature, 1, 8, f) != 8) + fatal("image_is_hdx(): Error reading signature\n"); + fclose(f); + if (signature == 0xD778A82044445459ll) + return 1; + else + return 0; + } else + return 1; + } else + return 0; } int image_is_vhd(const wchar_t *s, int check_signature) { - int len; - FILE* f; - char *ws = (char *) s; - wchar_t ext[5] = { 0, 0, 0, 0, 0 }; - len = wcslen(s); - if ((len < 4) || (s[0] == L'.')) - return 0; - memcpy(ext, ws + ((len - 4) << 1), 8); - if (wcscasecmp(ext, L".VHD") == 0) { - if (check_signature) { - f = plat_fopen((wchar_t*)s, L"rb"); - if (!f) - return 0; + int len; + FILE* f; + char *ws = (char *) s; + wchar_t ext[5] = { 0, 0, 0, 0, 0 }; + len = wcslen(s); + if ((len < 4) || (s[0] == L'.')) + return 0; + memcpy(ext, ws + ((len - 4) << 1), 8); + if (wcscasecmp(ext, L".VHD") == 0) { + if (check_signature) { + f = plat_fopen((wchar_t*)s, L"rb"); + if (!f) + return 0; - bool is_vhd = mvhd_file_is_vhd(f); - fclose(f); - return is_vhd ? 1 : 0; - } else - return 1; - } else - return 0; + bool is_vhd = mvhd_file_is_vhd(f); + fclose(f); + return is_vhd ? 1 : 0; + } else + return 1; + } else + return 0; } void hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size) { - /* Calculate the geometry from size (in MB), using the algorithm provided in - "Virtual Hard Disk Image Format Specification, Appendix: CHS Calculation" */ - uint64_t ts = ((uint64_t) size) << 11LL; - uint32_t spt, heads, cyl, cth; - if (ts > 65535 * 16 * 255) - ts = 65535 * 16 * 255; + /* Calculate the geometry from size (in MB), using the algorithm provided in + "Virtual Hard Disk Image Format Specification, Appendix: CHS Calculation" */ + uint64_t ts = ((uint64_t) size) << 11LL; + uint32_t spt, heads, cyl, cth; + if (ts > 65535 * 16 * 255) + ts = 65535 * 16 * 255; - if (ts >= 65535 * 16 * 63) { - spt = 255; - heads = 16; - cth = (uint32_t) (ts / spt); - } else { - spt = 17; - cth = (uint32_t) (ts / spt); - heads = (cth +1023) / 1024; - if (heads < 4) - heads = 4; - if ((cth >= (heads * 1024)) || (heads > 16)) { - spt = 31; - heads = 16; - cth = (uint32_t) (ts / spt); - } - if (cth >= (heads * 1024)) { - spt = 63; - heads = 16; - cth = (uint32_t) (ts / spt); - } - } - cyl = cth / heads; - *c = cyl; - *h = heads; - *s = spt; + if (ts >= 65535 * 16 * 63) { + spt = 255; + heads = 16; + cth = (uint32_t) (ts / spt); + } else { + spt = 17; + cth = (uint32_t) (ts / spt); + heads = (cth +1023) / 1024; + if (heads < 4) + heads = 4; + if ((cth >= (heads * 1024)) || (heads > 16)) { + spt = 31; + heads = 16; + cth = (uint32_t) (ts / spt); + } + if (cth >= (heads * 1024)) { + spt = 63; + heads = 16; + cth = (uint32_t) (ts / spt); + } + } + cyl = cth / heads; + *c = cyl; + *h = heads; + *s = spt; } static int prepare_new_hard_disk(uint8_t id, uint64_t full_size) { - uint64_t target_size = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file); + uint64_t target_size = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file); - uint32_t size; - uint32_t t, i; + uint32_t size; + uint32_t t, i; - t = (uint32_t) (target_size >> 20); /* Amount of 1 MB blocks. */ - size = (uint32_t) (target_size & 0xfffff); /* 1 MB mask. */ + t = (uint32_t) (target_size >> 20); /* Amount of 1 MB blocks. */ + size = (uint32_t) (target_size & 0xfffff); /* 1 MB mask. */ - empty_sector_1mb = (char *) malloc(1048576); - memset(empty_sector_1mb, 0, 1048576); + empty_sector_1mb = (char *) malloc(1048576); + memset(empty_sector_1mb, 0, 1048576); - /* Temporarily switch off suppression of seen messages so that the - progress gets displayed. */ - pclog_toggle_suppr(); - pclog("Writing image sectors: ["); + /* Temporarily switch off suppression of seen messages so that the + progress gets displayed. */ + pclog_toggle_suppr(); + pclog("Writing image sectors: ["); - /* First, write all the 1 MB blocks. */ - if (t > 0) { - for (i = 0; i < t; i++) { - fseek(hdd_images[id].file, 0, SEEK_END); - fwrite(empty_sector_1mb, 1, 1048576, hdd_images[id].file); - pclog("#"); - } - } + /* First, write all the 1 MB blocks. */ + if (t > 0) { + for (i = 0; i < t; i++) { + fseek(hdd_images[id].file, 0, SEEK_END); + fwrite(empty_sector_1mb, 1, 1048576, hdd_images[id].file); + pclog("#"); + } + } - /* Then, write the remainder. */ - if (size > 0) { - fseek(hdd_images[id].file, 0, SEEK_END); - fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); - pclog("#"); - } - pclog("]\n"); - /* Switch the suppression of seen messages back on. */ - pclog_toggle_suppr(); + /* Then, write the remainder. */ + if (size > 0) { + fseek(hdd_images[id].file, 0, SEEK_END); + fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); + pclog("#"); + } + pclog("]\n"); + /* Switch the suppression of seen messages back on. */ + pclog_toggle_suppr(); - free(empty_sector_1mb); + free(empty_sector_1mb); - hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; - hdd_images[id].loaded = 1; + hdd_images[id].loaded = 1; - return 1; + return 1; } void hdd_image_init(void) { - int i; + int i; - for (i = 0; i < HDD_NUM; i++) - memset(&hdd_images[i], 0, sizeof(hdd_image_t)); + for (i = 0; i < HDD_NUM; i++) + memset(&hdd_images[i], 0, sizeof(hdd_image_t)); } int hdd_image_load(int id) { - uint32_t sector_size = 512; - uint32_t zero = 0; - uint64_t signature = 0xD778A82044445459ll; - uint64_t full_size = 0; - uint64_t spt = 0, hpc = 0, tracks = 0; - int c, ret; - uint64_t s = 0; - wchar_t *fn = hdd[id].fn; - char fn_multibyte_buf[1200]; - int is_hdx[2] = { 0, 0 }; - int is_vhd[2] = { 0, 0 }; - int vhd_error = 0; + uint32_t sector_size = 512; + uint32_t zero = 0; + uint64_t signature = 0xD778A82044445459ll; + uint64_t full_size = 0; + uint64_t spt = 0, hpc = 0, tracks = 0; + int c, ret; + uint64_t s = 0; + wchar_t *fn = hdd[id].fn; + char fn_multibyte_buf[1200]; + int is_hdx[2] = { 0, 0 }; + int is_vhd[2] = { 0, 0 }; + int vhd_error = 0; - memset(empty_sector, 0, sizeof(empty_sector)); + memset(empty_sector, 0, sizeof(empty_sector)); - hdd_images[id].base = 0; + hdd_images[id].base = 0; - if (hdd_images[id].loaded) { - if (hdd_images[id].file) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - } - else if (hdd_images[id].vhd) { - mvhd_close(hdd_images[id].vhd); - hdd_images[id].vhd = NULL; - } - hdd_images[id].loaded = 0; - } + if (hdd_images[id].loaded) { + if (hdd_images[id].file) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } + else if (hdd_images[id].vhd) { + mvhd_close(hdd_images[id].vhd); + hdd_images[id].vhd = NULL; + } + hdd_images[id].loaded = 0; + } - is_hdx[0] = image_is_hdx(fn, 0); - is_hdx[1] = image_is_hdx(fn, 1); + is_hdx[0] = image_is_hdx(fn, 0); + is_hdx[1] = image_is_hdx(fn, 1); - is_vhd[0] = image_is_vhd(fn, 0); - is_vhd[1] = image_is_vhd(fn, 1); + is_vhd[0] = image_is_vhd(fn, 0); + is_vhd[1] = image_is_vhd(fn, 1); - hdd_images[id].pos = 0; + hdd_images[id].pos = 0; - /* Try to open existing hard disk image */ - if (fn[0] == '.') { - hdd_image_log("File name starts with .\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - hdd_images[id].file = plat_fopen(fn, L"rb+"); - if (hdd_images[id].file == NULL) { - /* Failed to open existing hard disk image */ - if (errno == ENOENT) { - /* Failed because it does not exist, - so try to create new file */ - if (hdd[id].wp) { - hdd_image_log("A write-protected image must exist\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } + /* Try to open existing hard disk image */ + if (fn[0] == '.') { + hdd_image_log("File name starts with .\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + hdd_images[id].file = plat_fopen(fn, L"rb+"); + if (hdd_images[id].file == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + if (hdd[id].wp) { + hdd_image_log("A write-protected image must exist\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } - hdd_images[id].file = plat_fopen(fn, L"wb+"); - if (hdd_images[id].file == NULL) { - hdd_image_log("Unable to open image\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } else { - if (image_is_hdi(fn)) { - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; - hdd_images[id].base = 0x1000; - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); - fwrite(&full_size, 1, 4, hdd_images[id].file); - fwrite(§or_size, 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); - for (c = 0; c < 0x3f8; c++) - fwrite(&zero, 1, 4, hdd_images[id].file); - hdd_images[id].type = HDD_IMAGE_HDI; - } else if (is_hdx[0]) { - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; - hdd_images[id].base = 0x28; - fwrite(&signature, 1, 8, hdd_images[id].file); - fwrite(&full_size, 1, 8, hdd_images[id].file); - fwrite(§or_size, 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - hdd_images[id].type = HDD_IMAGE_HDX; - } else if (is_vhd[0]) { - fclose(hdd_images[id].file); - MVHDGeom geometry; - geometry.cyl = hdd[id].tracks; - geometry.heads = hdd[id].hpc; - geometry.spt = hdd[id].spt; - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].file = plat_fopen(fn, L"wb+"); + if (hdd_images[id].file == NULL) { + hdd_image_log("Unable to open image\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } else { + if (image_is_hdi(fn)) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x1000; + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); + fwrite(&full_size, 1, 4, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + for (c = 0; c < 0x3f8; c++) + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = HDD_IMAGE_HDI; + } else if (is_hdx[0]) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x28; + fwrite(&signature, 1, 8, hdd_images[id].file); + fwrite(&full_size, 1, 8, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = HDD_IMAGE_HDX; + } else if (is_vhd[0]) { + fclose(hdd_images[id].file); + MVHDGeom geometry; + geometry.cyl = hdd[id].tracks; + geometry.heads = hdd[id].hpc; + geometry.spt = hdd[id].spt; + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; - wcstombs(fn_multibyte_buf, fn, sizeof fn_multibyte_buf); - hdd_images[id].vhd = mvhd_create_fixed(fn_multibyte_buf, geometry, &vhd_error, NULL); - if (hdd_images[id].vhd == NULL) - fatal("hdd_image_load(): VHD: Could not create VHD : %s\n", mvhd_strerr(vhd_error)); + wcstombs(fn_multibyte_buf, fn, sizeof fn_multibyte_buf); + hdd_images[id].vhd = mvhd_create_fixed(fn_multibyte_buf, geometry, &vhd_error, NULL); + if (hdd_images[id].vhd == NULL) + fatal("hdd_image_load(): VHD: Could not create VHD : %s\n", mvhd_strerr(vhd_error)); - hdd_images[id].type = HDD_IMAGE_VHD; - return 1; - } else { - hdd_images[id].type = HDD_IMAGE_RAW; - } - hdd_images[id].last_sector = 0; - } + hdd_images[id].type = HDD_IMAGE_VHD; + return 1; + } else { + hdd_images[id].type = HDD_IMAGE_RAW; + } + hdd_images[id].last_sector = 0; + } - s = full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; + s = full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; - ret = prepare_new_hard_disk(id, full_size); - return ret; - } else { - /* Failed for another reason */ - hdd_image_log("Failed for another reason\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - } else { - if (image_is_hdi(fn)) { - if (fseeko64(hdd_images[id].file, 0x8, SEEK_SET) == -1) - fatal("hdd_image_load(): HDI: Error seeking to offset 0x8\n"); - if (fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading base offset\n"); - if (fseeko64(hdd_images[id].file, 0xC, SEEK_SET) == -1) - fatal("hdd_image_load(): HDI: Error seeking to offest 0xC\n"); - full_size = 0LL; - if (fread(&full_size, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading full size\n"); - if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) - fatal("hdd_image_load(): HDI: Error seeking to offset 0x10\n"); - if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading sector size\n"); - if (sector_size != 512) { - /* Sector size is not 512 */ - hdd_image_log("HDI: Sector size is not 512\n"); - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - if (fread(&spt, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); - if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); - if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading number of tracks\n"); - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; - hdd_images[id].type = HDD_IMAGE_HDI; - } else if (is_hdx[1]) { - hdd_images[id].base = 0x28; - if (fseeko64(hdd_images[id].file, 8, SEEK_SET) == -1) - fatal("hdd_image_load(): HDX: Error seeking to offset 0x8\n"); - if (fread(&full_size, 1, 8, hdd_images[id].file) != 8) - fatal("hdd_image_load(): HDX: Error reading full size\n"); - if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) - fatal("hdd_image_load(): HDX: Error seeking to offset 0x10\n"); - if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDX: Error reading sector size\n"); - if (sector_size != 512) { - /* Sector size is not 512 */ - hdd_image_log("HDX: Sector size is not 512\n"); - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - if (fread(&spt, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); - if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); - if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) - fatal("hdd_image_load(): HDX: Error reading number of tracks\n"); - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; - hdd_images[id].type = HDD_IMAGE_HDX; - } else if (is_vhd[1]) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - wcstombs(fn_multibyte_buf, fn, sizeof fn_multibyte_buf); - hdd_images[id].vhd = mvhd_open(fn_multibyte_buf, (bool)0, &vhd_error); - if (hdd_images[id].vhd == NULL) - { - if (vhd_error == MVHD_ERR_FILE) - fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn_multibyte_buf, strerror(mvhd_errno)); - else - fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn_multibyte_buf, mvhd_strerr(vhd_error)); - } - else if (vhd_error == MVHD_ERR_TIMESTAMP) - { - fatal("hdd_image_load(): VHD: Parent/child timestamp mismatch for VHD file '%s'\n", fn_multibyte_buf); - } + ret = prepare_new_hard_disk(id, full_size); + return ret; + } else { + /* Failed for another reason */ + hdd_image_log("Failed for another reason\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + } else { + if (image_is_hdi(fn)) { + if (fseeko64(hdd_images[id].file, 0x8, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offset 0x8\n"); + if (fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading base offset\n"); + if (fseeko64(hdd_images[id].file, 0xC, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offest 0xC\n"); + full_size = 0LL; + if (fread(&full_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading full size\n"); + if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) + fatal("hdd_image_load(): HDI: Error seeking to offset 0x10\n"); + if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sector size\n"); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDI: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + if (fread(&spt, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); + if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); + if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading number of tracks\n"); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + hdd_images[id].type = HDD_IMAGE_HDI; + } else if (is_hdx[1]) { + hdd_images[id].base = 0x28; + if (fseeko64(hdd_images[id].file, 8, SEEK_SET) == -1) + fatal("hdd_image_load(): HDX: Error seeking to offset 0x8\n"); + if (fread(&full_size, 1, 8, hdd_images[id].file) != 8) + fatal("hdd_image_load(): HDX: Error reading full size\n"); + if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1) + fatal("hdd_image_load(): HDX: Error seeking to offset 0x10\n"); + if (fread(§or_size, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDX: Error reading sector size\n"); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDX: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + if (fread(&spt, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading sectors per track\n"); + if (fread(&hpc, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n"); + if (fread(&tracks, 1, 4, hdd_images[id].file) != 4) + fatal("hdd_image_load(): HDX: Error reading number of tracks\n"); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + hdd_images[id].type = HDD_IMAGE_HDX; + } else if (is_vhd[1]) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + wcstombs(fn_multibyte_buf, fn, sizeof fn_multibyte_buf); + hdd_images[id].vhd = mvhd_open(fn_multibyte_buf, (bool)0, &vhd_error); + if (hdd_images[id].vhd == NULL) { + if (vhd_error == MVHD_ERR_FILE) + fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn_multibyte_buf, strerror(mvhd_errno)); + else + fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn_multibyte_buf, mvhd_strerr(vhd_error)); + } + else if (vhd_error == MVHD_ERR_TIMESTAMP) { + fatal("hdd_image_load(): VHD: Parent/child timestamp mismatch for VHD file '%s'\n", fn_multibyte_buf); + } - full_size = hdd_images[id].vhd->footer.curr_sz; - hdd[id].tracks = hdd_images[id].vhd->footer.geom.cyl; - hdd[id].hpc = hdd_images[id].vhd->footer.geom.heads; - hdd[id].spt = hdd_images[id].vhd->footer.geom.spt; - hdd_images[id].type = HDD_IMAGE_VHD; - /* If we're here, this means there is a valid VHD footer in the - image, which means that by definition, all valid sectors - are there. */ - hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; - hdd_images[id].loaded = 1; - return 1; - } else { - full_size = ((uint64_t) hdd[id].spt) * - ((uint64_t) hdd[id].hpc) * - ((uint64_t) hdd[id].tracks) << 9LL; - hdd_images[id].type = HDD_IMAGE_RAW; - } - } + full_size = hdd_images[id].vhd->footer.curr_sz; + hdd[id].tracks = hdd_images[id].vhd->footer.geom.cyl; + hdd[id].hpc = hdd_images[id].vhd->footer.geom.heads; + hdd[id].spt = hdd_images[id].vhd->footer.geom.spt; + hdd_images[id].type = HDD_IMAGE_VHD; + /* If we're here, this means there is a valid VHD footer in the + image, which means that by definition, all valid sectors + are there. */ + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + hdd_images[id].loaded = 1; + return 1; + } else { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].type = HDD_IMAGE_RAW; + } + } - if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1) - fatal("hdd_image_load(): Error seeking to the end of file\n"); - s = ftello64(hdd_images[id].file); - if (s < (full_size + hdd_images[id].base)) - ret = prepare_new_hard_disk(id, full_size); - else { - hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; - hdd_images[id].loaded = 1; - ret = 1; - } + if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1) + fatal("hdd_image_load(): Error seeking to the end of file\n"); + s = ftello64(hdd_images[id].file); + if (s < (full_size + hdd_images[id].base)) + ret = prepare_new_hard_disk(id, full_size); + else { + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + hdd_images[id].loaded = 1; + ret = 1; + } - return ret; + return ret; } void hdd_image_seek(uint8_t id, uint32_t sector) { - off64_t addr = sector; - addr = (uint64_t)sector << 9LL; + off64_t addr = sector; + addr = (uint64_t)sector << 9LL; - hdd_images[id].pos = sector; - if (hdd_images[id].type != HDD_IMAGE_VHD) { - if (fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET) == -1) - fatal("hdd_image_seek(): Error seeking\n"); - } + hdd_images[id].pos = sector; + if (hdd_images[id].type != HDD_IMAGE_VHD) { + if (fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET) == -1) + fatal("hdd_image_seek(): Error seeking\n"); + } } void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - if (hdd_images[id].type == HDD_IMAGE_VHD) { - int non_transferred_sectors = mvhd_read_sectors(hdd_images[id].vhd, sector, count, buffer); - hdd_images[id].pos = sector + count - non_transferred_sectors - 1; - } else { - int i; + if (hdd_images[id].type == HDD_IMAGE_VHD) { + int non_transferred_sectors = mvhd_read_sectors(hdd_images[id].vhd, sector, count, buffer); + hdd_images[id].pos = sector + count - non_transferred_sectors - 1; + } else { + int i; - if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { - fatal("Hard disk image %i: Read error during seek\n", id); - return; - } + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Read error during seek\n", id); + return; + } - for (i = 0; i < count; i++) { - if (feof(hdd_images[id].file)) - break; + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; - hdd_images[id].pos = sector + i; - fread(buffer + (i << 9), 1, 512, hdd_images[id].file); - } - } + hdd_images[id].pos = sector + i; + fread(buffer + (i << 9), 1, 512, hdd_images[id].file); + } + } } uint32_t hdd_sectors(uint8_t id) { - if (hdd_images[id].type == HDD_IMAGE_VHD) { - return (uint32_t) (hdd_images[id].vhd->footer.curr_sz >> 9); - } else { - fseeko64(hdd_images[id].file, 0, SEEK_END); - return (uint32_t)((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9); - } + if (hdd_images[id].type == HDD_IMAGE_VHD) { + return (uint32_t) (hdd_images[id].vhd->footer.curr_sz >> 9); + } else { + fseeko64(hdd_images[id].file, 0, SEEK_END); + return (uint32_t)((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9); + } } int hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - uint32_t transfer_sectors = count; - uint32_t sectors = hdd_sectors(id); + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); - if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; - hdd_image_read(id, sector, transfer_sectors, buffer); + hdd_image_read(id, sector, transfer_sectors, buffer); - if (count != transfer_sectors) - return 1; - return 0; + if (count != transfer_sectors) + return 1; + return 0; } void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - if (hdd_images[id].type == HDD_IMAGE_VHD) { - int non_transferred_sectors = mvhd_write_sectors(hdd_images[id].vhd, sector, count, buffer); - hdd_images[id].pos = sector + count - non_transferred_sectors - 1; - } else { - int i; + if (hdd_images[id].type == HDD_IMAGE_VHD) { + int non_transferred_sectors = mvhd_write_sectors(hdd_images[id].vhd, sector, count, buffer); + hdd_images[id].pos = sector + count - non_transferred_sectors - 1; + } else { + int i; - if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { - fatal("Hard disk image %i: Write error during seek\n", id); - return; - } + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Write error during seek\n", id); + return; + } - for (i = 0; i < count; i++) { - if (feof(hdd_images[id].file)) - break; + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; - hdd_images[id].pos = sector + i; - fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file); - } - } + hdd_images[id].pos = sector + i; + fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file); + } + } } int hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - uint32_t transfer_sectors = count; - uint32_t sectors = hdd_sectors(id); + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); - if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; - hdd_image_write(id, sector, transfer_sectors, buffer); + hdd_image_write(id, sector, transfer_sectors, buffer); - if (count != transfer_sectors) - return 1; - return 0; + if (count != transfer_sectors) + return 1; + return 0; } void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) { - if (hdd_images[id].type == HDD_IMAGE_VHD) { - int non_transferred_sectors = mvhd_format_sectors(hdd_images[id].vhd, sector, count); - hdd_images[id].pos = sector + count - non_transferred_sectors - 1; - } else { - uint32_t i = 0; + if (hdd_images[id].type == HDD_IMAGE_VHD) { + int non_transferred_sectors = mvhd_format_sectors(hdd_images[id].vhd, sector, count); + hdd_images[id].pos = sector + count - non_transferred_sectors - 1; + } else { + uint32_t i = 0; - memset(empty_sector, 0, 512); + memset(empty_sector, 0, 512); - if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { - fatal("Hard disk image %i: Zero error during seek\n", id); - return; - } + if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) { + fatal("Hard disk image %i: Zero error during seek\n", id); + return; + } - for (i = 0; i < count; i++) { - if (feof(hdd_images[id].file)) - break; + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; - hdd_images[id].pos = sector + i; - fwrite(empty_sector, 512, 1, hdd_images[id].file); - } - } + hdd_images[id].pos = sector + i; + fwrite(empty_sector, 512, 1, hdd_images[id].file); + } + } } int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) { - uint32_t transfer_sectors = count; - uint32_t sectors = hdd_sectors(id); + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); - if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; - hdd_image_zero(id, sector, transfer_sectors); + hdd_image_zero(id, sector, transfer_sectors); - if (count != transfer_sectors) - return 1; - return 0; + if (count != transfer_sectors) + return 1; + return 0; } uint32_t hdd_image_get_last_sector(uint8_t id) { - return hdd_images[id].last_sector; + return hdd_images[id].last_sector; } uint32_t hdd_image_get_pos(uint8_t id) { - return hdd_images[id].pos; + return hdd_images[id].pos; } uint8_t hdd_image_get_type(uint8_t id) { - return hdd_images[id].type; + return hdd_images[id].type; } void hdd_image_unload(uint8_t id, int fn_preserve) { - if (wcslen(hdd[id].fn) == 0) - return; + if (wcslen(hdd[id].fn) == 0) + return; - if (hdd_images[id].loaded) { - if (hdd_images[id].file != NULL) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - } else if (hdd_images[id].vhd != NULL) { - mvhd_close(hdd_images[id].vhd); - hdd_images[id].vhd = NULL; - } - hdd_images[id].loaded = 0; - } + if (hdd_images[id].loaded) { + if (hdd_images[id].file != NULL) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } else if (hdd_images[id].vhd != NULL) { + mvhd_close(hdd_images[id].vhd); + hdd_images[id].vhd = NULL; + } + hdd_images[id].loaded = 0; + } - hdd_images[id].last_sector = -1; + hdd_images[id].last_sector = -1; - memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); - if (fn_preserve) - wcscpy(hdd[id].prev_fn, hdd[id].fn); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); + if (fn_preserve) + wcscpy(hdd[id].prev_fn, hdd[id].fn); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); } void hdd_image_close(uint8_t id) { - hdd_image_log("hdd_image_close(%i)\n", id); + hdd_image_log("hdd_image_close(%i)\n", id); - if (!hdd_images[id].loaded) - return; + if (!hdd_images[id].loaded) + return; - if (hdd_images[id].file != NULL) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - } else if (hdd_images[id].vhd != NULL) { - mvhd_close(hdd_images[id].vhd); - hdd_images[id].vhd = NULL; - } + if (hdd_images[id].file != NULL) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } else if (hdd_images[id].vhd != NULL) { + mvhd_close(hdd_images[id].vhd); + hdd_images[id].vhd = NULL; + } - memset(&hdd_images[id], 0, sizeof(hdd_image_t)); - hdd_images[id].loaded = 0; + memset(&hdd_images[id], 0, sizeof(hdd_image_t)); + hdd_images[id].loaded = 0; } diff --git a/src/include/86box/language.h b/src/include/86box/language.h index c4a4b64a5..c8d77dd6c 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -140,12 +140,12 @@ #define IDS_4119 4119 // "Unsupported disk image" #define IDS_4120 4120 // "Overwrite" #define IDS_4121 4121 // "Don't Overwrite" -#define IDS_4122 4122 // "Raw image (.img)" -#define IDS_4123 4123 // "HDI image (.hdi)" -#define IDS_4124 4124 // "HDX image (.hdx)" -#define IDS_4125 4125 // "Fixed-size VHD (.vhd)" -#define IDS_4126 4126 // "Dynamic-size VHD (.vhd)" -#define IDS_4127 4127 // "Differencing VHD (.vhd)" +#define IDS_4122 4122 // "Raw image (.img)" +#define IDS_4123 4123 // "HDI image (.hdi)" +#define IDS_4124 4124 // "HDX image (.hdx)" +#define IDS_4125 4125 // "Fixed-size VHD (.vhd)" +#define IDS_4126 4126 // "Dynamic-size VHD (.vhd)" +#define IDS_4127 4127 // "Differencing VHD (.vhd)" #define IDS_4352 4352 // "MFM/RLL" #define IDS_4353 4353 // "XT IDE" diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index b0e194bb8..25c087fda 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -100,13 +100,13 @@ #define IDT_1766 1766 /* Board #4: */ #define IDT_1767 1767 /* ISA RTC: */ #define IDT_1768 1768 /* Ext FD Controller: */ -#define IDT_1769 1769 /* MO drives: */ -#define IDT_1770 1770 /* Bus: */ -#define IDT_1771 1771 /* ID: */ -#define IDT_1772 1772 /* Channel */ -#define IDT_1773 1773 /* Type: */ -#define IDT_1774 1774 /* Image Format: */ -#define IDT_1775 1775 /* Block Size: */ +#define IDT_1769 1769 /* MO drives: */ +#define IDT_1770 1770 /* Bus: */ +#define IDT_1771 1771 /* ID: */ +#define IDT_1772 1772 /* Channel */ +#define IDT_1773 1773 /* Type: */ +#define IDT_1774 1774 /* Image Format: */ +#define IDT_1775 1775 /* Block Size: */ /* @@ -220,8 +220,8 @@ #define IDC_EDIT_HD_SIZE 1164 #define IDC_COMBO_HD_TYPE 1165 #define IDC_PBAR_IMG_CREATE 1166 -#define IDC_COMBO_HD_IMG_FORMAT 1167 -#define IDC_COMBO_HD_BLOCK_SIZE 1168 +#define IDC_COMBO_HD_IMG_FORMAT 1167 +#define IDC_COMBO_HD_BLOCK_SIZE 1168 #define IDC_REMOV_DEVICES 1170 /* floppy and cd-rom drives config */ #define IDC_LIST_FLOPPY_DRIVES 1171 diff --git a/src/win/win_settings.c b/src/win/win_settings.c index a23690b1d..7452aee2f 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -2405,12 +2405,12 @@ HWND vhd_progress_hdlg; static void vhd_progress_callback(uint32_t current_sector, uint32_t total_sectors) { MSG msg; - HWND h = GetDlgItem(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE); + HWND h = GetDlgItem(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE); SendMessage(h, PBM_SETPOS, (WPARAM) current_sector, (LPARAM) 0); while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { TranslateMessage(&msg); DispatchMessage(&msg); - } + } } /* If the disk geometry requested in the 86Box GUI is not compatible with the internal VHD geometry, @@ -2420,139 +2420,129 @@ static void vhd_progress_callback(uint32_t current_sector, uint32_t total_sector */ static void adjust_86box_geometry_for_vhd(MVHDGeom *_86box_geometry, MVHDGeom *vhd_geometry) { - if (_86box_geometry->cyl <= 65535) { - vhd_geometry->cyl = _86box_geometry->cyl; - vhd_geometry->heads = _86box_geometry->heads; - vhd_geometry->spt = _86box_geometry->spt; - return; - } + if (_86box_geometry->cyl <= 65535) { + vhd_geometry->cyl = _86box_geometry->cyl; + vhd_geometry->heads = _86box_geometry->heads; + vhd_geometry->spt = _86box_geometry->spt; + return; + } - int desired_sectors = _86box_geometry->cyl * _86box_geometry->heads * _86box_geometry->spt; - if (desired_sectors > 267321600) - desired_sectors = 267321600; + int desired_sectors = _86box_geometry->cyl * _86box_geometry->heads * _86box_geometry->spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; - int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ - if (remainder > 0) - desired_sectors += (85680 - remainder); + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors += (85680 - remainder); - _86box_geometry->cyl = desired_sectors / (16 * 63); - _86box_geometry->heads = 16; - _86box_geometry->spt = 63; + _86box_geometry->cyl = desired_sectors / (16 * 63); + _86box_geometry->heads = 16; + _86box_geometry->spt = 63; - vhd_geometry->cyl = desired_sectors / (16 * 255); - vhd_geometry->heads = 16; - vhd_geometry->spt = 255; + vhd_geometry->cyl = desired_sectors / (16 * 255); + vhd_geometry->heads = 16; + vhd_geometry->spt = 255; } static void adjust_vhd_geometry_for_86box(MVHDGeom *vhd_geometry) { - if (vhd_geometry->spt <= 63) - return; + if (vhd_geometry->spt <= 63) + return; - int desired_sectors = vhd_geometry->cyl * vhd_geometry->heads * vhd_geometry->spt; - if (desired_sectors > 267321600) - desired_sectors = 267321600; + int desired_sectors = vhd_geometry->cyl * vhd_geometry->heads * vhd_geometry->spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; - int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ - if (remainder > 0) - desired_sectors -= remainder; + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors -= remainder; - vhd_geometry->cyl = desired_sectors / (16 * 63); - vhd_geometry->heads = 16; - vhd_geometry->spt = 63; + vhd_geometry->cyl = desired_sectors / (16 * 63); + vhd_geometry->heads = 16; + vhd_geometry->spt = 63; } static MVHDGeom create_drive_vhd_fixed(char* filename, int cyl, int heads, int spt) { - MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; - MVHDGeom vhd_geometry; - adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); + MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom vhd_geometry; + adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); - HWND h = GetDlgItem(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE); - settings_show_window(vhd_progress_hdlg, IDT_1731, FALSE); - settings_show_window(vhd_progress_hdlg, IDC_EDIT_HD_FILE_NAME, FALSE); - settings_show_window(vhd_progress_hdlg, IDC_CFILE, FALSE); - settings_show_window(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE, TRUE); - settings_enable_window(vhd_progress_hdlg, IDT_1752, TRUE); - SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) vhd_geometry.cyl * vhd_geometry.heads * vhd_geometry.spt); - SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); + HWND h = GetDlgItem(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE); + settings_show_window(vhd_progress_hdlg, IDT_1731, FALSE); + settings_show_window(vhd_progress_hdlg, IDC_EDIT_HD_FILE_NAME, FALSE); + settings_show_window(vhd_progress_hdlg, IDC_CFILE, FALSE); + settings_show_window(vhd_progress_hdlg, IDC_PBAR_IMG_CREATE, TRUE); + settings_enable_window(vhd_progress_hdlg, IDT_1752, TRUE); + SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) vhd_geometry.cyl * vhd_geometry.heads * vhd_geometry.spt); + SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); - int vhd_error = 0; - MVHDMeta *vhd = mvhd_create_fixed(filename, vhd_geometry, &vhd_error, vhd_progress_callback); - if (vhd == NULL) - { - _86box_geometry.cyl = 0; - _86box_geometry.heads = 0; - _86box_geometry.spt = 0; - } - else - { - mvhd_close(vhd); - } + int vhd_error = 0; + MVHDMeta *vhd = mvhd_create_fixed(filename, vhd_geometry, &vhd_error, vhd_progress_callback); + if (vhd == NULL) { + _86box_geometry.cyl = 0; + _86box_geometry.heads = 0; + _86box_geometry.spt = 0; + } else { + mvhd_close(vhd); + } - return _86box_geometry; + return _86box_geometry; } static MVHDGeom create_drive_vhd_dynamic(char* filename, int cyl, int heads, int spt, int blocksize) { - MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; - MVHDGeom vhd_geometry; - adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); - int vhd_error = 0; - MVHDCreationOptions options; - options.block_size_in_sectors = blocksize; - options.path = filename; - options.size_in_bytes = 0; - options.geometry = vhd_geometry; - options.type = MVHD_TYPE_DYNAMIC; + MVHDGeom _86box_geometry = { .cyl = cyl, .heads = heads, .spt = spt }; + MVHDGeom vhd_geometry; + adjust_86box_geometry_for_vhd(&_86box_geometry, &vhd_geometry); + int vhd_error = 0; + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = filename; + options.size_in_bytes = 0; + options.geometry = vhd_geometry; + options.type = MVHD_TYPE_DYNAMIC; - MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); - if (vhd == NULL) - { - _86box_geometry.cyl = 0; - _86box_geometry.heads = 0; - _86box_geometry.spt = 0; - } - else - { - mvhd_close(vhd); - } + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + if (vhd == NULL) { + _86box_geometry.cyl = 0; + _86box_geometry.heads = 0; + _86box_geometry.spt = 0; + } else { + mvhd_close(vhd); + } - return _86box_geometry; + return _86box_geometry; } static MVHDGeom create_drive_vhd_diff(char* filename, char* parent_filename, int blocksize) { - int vhd_error = 0; - MVHDCreationOptions options; - options.block_size_in_sectors = blocksize; - options.path = filename; - options.parent_path = parent_filename; - options.type = MVHD_TYPE_DIFF; + int vhd_error = 0; + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = filename; + options.parent_path = parent_filename; + options.type = MVHD_TYPE_DIFF; - MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); - MVHDGeom vhd_geometry; - if (vhd == NULL) - { - vhd_geometry.cyl = 0; - vhd_geometry.heads = 0; - vhd_geometry.spt = 0; - } - else - { - vhd_geometry = mvhd_get_geometry(vhd); + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + MVHDGeom vhd_geometry; + if (vhd == NULL) { + vhd_geometry.cyl = 0; + vhd_geometry.heads = 0; + vhd_geometry.spt = 0; + } else { + vhd_geometry = mvhd_get_geometry(vhd); - if (vhd_geometry.spt > 63) - { - vhd_geometry.cyl = mvhd_calc_size_sectors(&vhd_geometry) / (16 * 63); - vhd_geometry.heads = 16; - vhd_geometry.spt = 63; - } + if (vhd_geometry.spt > 63) { + vhd_geometry.cyl = mvhd_calc_size_sectors(&vhd_geometry) / (16 * 63); + vhd_geometry.heads = 16; + vhd_geometry.spt = 63; + } - mvhd_close(vhd); - } + mvhd_close(vhd); + } - return vhd_geometry; + return vhd_geometry; } @@ -2563,27 +2553,27 @@ static BOOL CALLBACK #endif win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; - FILE *f; - uint32_t temp, i = 0, sector_size = 512; - uint32_t zero = 0, base = 0x1000; - uint64_t signature = 0xD778A82044445459ll; - uint64_t r = 0; - char *big_buf; + HWND h; + FILE *f; + uint32_t temp, i = 0, sector_size = 512; + uint32_t zero = 0, base = 0x1000; + uint64_t signature = 0xD778A82044445459ll; + uint64_t r = 0; + char *big_buf; char hd_file_name_multibyte[1200]; - int b = 0; + int b = 0; int vhd_error = 0; - uint8_t channel = 0; - uint8_t id = 0; - wchar_t *twcs; - MSG msg; + uint8_t channel = 0; + uint8_t id = 0; + wchar_t *twcs; + MSG msg; int img_format, block_size; WCHAR text_buf[256]; RECT rect; POINT point; int dlg_height_adjust; - switch (message) { + switch (message) { case WM_INITDIALOG: memset(hd_file_name, 0, sizeof(hd_file_name)); @@ -2615,8 +2605,8 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"HDX image (.hdx)"); settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Fixed-size VHD (.vhd)"); settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Dynamic-size VHD (.vhd)"); - settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Differencing VHD (.vhd)"); - settings_set_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT, 0); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Differencing VHD (.vhd)"); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT, 0); settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, (LPARAM) L"Large blocks (2 MB)"); settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, (LPARAM) L"Small blocks (512 KB)"); @@ -2728,9 +2718,9 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM sector_size = 512; if (!(existing & 1) && (wcslen(hd_file_name) > 0)) { - if (size > 0x1FFFFFFE00ll) { + if (size > 0x1FFFFFFE00ll) { settings_msgbox_header(MBX_ERROR, (wchar_t *) IDS_4116, (wchar_t *) IDS_4105); - return TRUE; + return TRUE; } img_format = settings_get_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT); @@ -2769,14 +2759,14 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM MVHDGeom _86box_geometry; block_size = settings_get_cur_sel(hdlg, IDC_COMBO_HD_BLOCK_SIZE) == 0 ? MVHD_BLOCK_LARGE : MVHD_BLOCK_SMALL; switch (img_format) { - case 3: + case 3: vhd_progress_hdlg = hdlg; _86box_geometry = create_drive_vhd_fixed(hd_file_name_multibyte, tracks, hpc, spt); break; - case 4: - _86box_geometry = create_drive_vhd_dynamic(hd_file_name_multibyte, tracks, hpc, spt, block_size); + case 4: + _86box_geometry = create_drive_vhd_dynamic(hd_file_name_multibyte, tracks, hpc, spt, block_size); break; - case 5: + case 5: if (file_dlg_w(hdlg, L"VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0", L"", L"Select the parent VHD",0)) { return TRUE; } @@ -2793,11 +2783,11 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM hard_disk_added = 1; EndDialog(hdlg, 0); - return TRUE; + return TRUE; } big_buf = (char *) malloc(1048576); - memset(big_buf, 0, 1048576); + memset(big_buf, 0, 1048576); r = size >> 20; size &= 0xfffff; @@ -2831,12 +2821,12 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM DispatchMessage(&msg); } } - } + } free(big_buf); fclose(f); - settings_msgbox_header(MBX_INFO, (wchar_t *) IDS_4113, (wchar_t *) IDS_4117); + settings_msgbox_header(MBX_INFO, (wchar_t *) IDS_4113, (wchar_t *) IDS_4117); } hard_disk_added = 1; @@ -2849,7 +2839,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM EndDialog(hdlg, 0); return TRUE; - case IDC_CFILE: + case IDC_CFILE: if (!file_dlg_w(hdlg, plat_get_string(IDS_4106), L"", NULL, !(existing & 1))) { if (!wcschr(wopenfilestring, L'.')) { if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { @@ -2892,32 +2882,31 @@ hdd_add_file_open_error: fread(&tracks, 1, 4, f); } else if (image_is_vhd(wopenfilestring, 1)) { fclose(f); - wcstombs(hd_file_name_multibyte, wopenfilestring, sizeof hd_file_name_multibyte); + wcstombs(hd_file_name_multibyte, wopenfilestring, sizeof hd_file_name_multibyte); MVHDMeta* vhd = mvhd_open(hd_file_name_multibyte, 0, &vhd_error); if (vhd == NULL) { settings_msgbox_header(MBX_ERROR, (existing & 1) ? (wchar_t *) IDS_4114 : (wchar_t *) IDS_4115, (existing & 1) ? (wchar_t *) IDS_4107 : (wchar_t *) IDS_4108); return TRUE; } else if (vhd_error == MVHD_ERR_TIMESTAMP) { wchar_t* ts_warning = - L"WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH!\n\n" - "This could indicate that the parent image was modified after this VHD was created.\n\n" - "This could also happen if the VHD files were moved/copied, or the differencing VHD was created with DiskPart.\n\n" - "Do you wish to fix this error after a file copy or DiskPart creation?"; + L"WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH!\n\n" + "This could indicate that the parent image was modified after this VHD was created.\n\n" + "This could also happen if the VHD files were moved/copied, or the differencing VHD was created with DiskPart.\n\n" + "Do you wish to fix this error after a file copy or DiskPart creation?"; if (settings_msgbox_ex(MBX_QUESTION_YN, L"VHD Timestamp Mismatch", ts_warning, NULL, NULL, NULL) != 0) { int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhd_error); - if (ts_res != 0) - { - settings_msgbox_header(MBX_ERROR, L"Error", L"Could not fix VHD timestamp."); + if (ts_res != 0) { + settings_msgbox_header(MBX_ERROR, L"Error", L"Could not fix VHD timestamp."); mvhd_close(vhd); return TRUE; } } else { mvhd_close(vhd); return TRUE; - } + } } - MVHDGeom vhd_geom = mvhd_get_geometry(vhd); + MVHDGeom vhd_geom = mvhd_get_geometry(vhd); adjust_vhd_geometry_for_86box(&vhd_geom); tracks = vhd_geom.cyl; hpc = vhd_geom.heads; @@ -2951,7 +2940,7 @@ hdd_add_file_open_error: } if ((spt > max_spt) || (hpc > max_hpc) || (tracks > max_tracks)) - goto hdd_add_file_open_error; + goto hdd_add_file_open_error; no_update = 1; set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); @@ -3231,7 +3220,7 @@ hdd_add_file_open_error: break; case IDC_COMBO_HD_IMG_FORMAT: img_format = settings_get_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT); - + no_update = 1; if (img_format == 5) { /* They switched to a diff VHD; disable the geometry fields. */ settings_enable_window(hdlg, IDC_EDIT_HD_SPT, FALSE); @@ -3245,7 +3234,7 @@ hdd_add_file_open_error: settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, FALSE); settings_reset_content(hdlg, IDC_COMBO_HD_TYPE); settings_add_string(hdlg, IDC_COMBO_HD_TYPE, (LPARAM) L"(use parent)"); - settings_set_cur_sel(hdlg, IDC_COMBO_HD_TYPE, 0); + settings_set_cur_sel(hdlg, IDC_COMBO_HD_TYPE, 0); } else { get_edit_box_text_contents(hdlg, IDC_EDIT_HD_SPT, text_buf, 256); if (!wcscmp(text_buf, L"(N/A)")) { @@ -3257,19 +3246,16 @@ hdd_add_file_open_error: set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, 1023); settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, TRUE); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) ((uint64_t)17 * 15 * 1023 * 512 >> 20)); - settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, TRUE); - hdconf_initialize_hdt_combo(hdlg); + settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, TRUE); + hdconf_initialize_hdt_combo(hdlg); } } no_update = 0; - if (img_format == 4 || img_format == 5) /* For dynamic and diff VHDs, show the block size dropdown. */ - { + if (img_format == 4 || img_format == 5) { /* For dynamic and diff VHDs, show the block size dropdown. */ settings_show_window(hdlg, IDC_COMBO_HD_BLOCK_SIZE, TRUE); - settings_show_window(hdlg, IDT_1775, TRUE); - } - else /* Hide it otherwise. */ - { + settings_show_window(hdlg, IDT_1775, TRUE); + } else { /* Hide it otherwise. */ settings_show_window(hdlg, IDC_COMBO_HD_BLOCK_SIZE, FALSE); settings_show_window(hdlg, IDT_1775, FALSE); } @@ -3277,9 +3263,9 @@ hdd_add_file_open_error: } return FALSE; - } + } - return FALSE; + return FALSE; } From 84df433c6a61108ac120d0faae098866ba99f502 Mon Sep 17 00:00:00 2001 From: Stephen McKinney Date: Thu, 19 Nov 2020 01:11:52 -0600 Subject: [PATCH 05/67] Use string resources instead of hard-coded strings. --- src/include/86box/language.h | 9 ++++++++- src/win/86Box.rc | 19 ++++++++++++------ src/win/win_settings.c | 39 ++++++++++++------------------------ 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/include/86box/language.h b/src/include/86box/language.h index c8d77dd6c..d8444a3a3 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -146,6 +146,13 @@ #define IDS_4125 4125 // "Fixed-size VHD (.vhd)" #define IDS_4126 4126 // "Dynamic-size VHD (.vhd)" #define IDS_4127 4127 // "Differencing VHD (.vhd)" +#define IDS_4128 4128 // "Large blocks (2 MB)" +#define IDS_4129 4129 // "Small blocks (512 KB)" +#define IDS_4130 4130 // "VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0" +#define IDS_4131 4131 // "Select the parent VHD" +#define IDS_4132 4132 // "WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH..." +#define IDS_4133 4133 // "VHD Timestamp Mismatch" +#define IDS_4134 4134 // "Could not fix VHD timestamp." #define IDS_4352 4352 // "MFM/RLL" #define IDS_4353 4353 // "XT IDE" @@ -215,7 +222,7 @@ #define STR_NUM_2048 92 #define STR_NUM_3072 11 -#define STR_NUM_4096 32 +#define STR_NUM_4096 39 #define STR_NUM_4352 6 #define STR_NUM_4608 6 #define STR_NUM_5120 1 diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 873cb9e1f..509980b62 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -1061,12 +1061,19 @@ BEGIN IDS_4119 "Unsupported disk image" IDS_4120 "Overwrite" IDS_4121 "Don't Overwrite" - IDS_4122 "Raw image (.img)" - IDS_4123 "HDI image (.hdi)" - IDS_4124 "HDX image (.hdx)" - IDS_4125 "Fixed-size VHD (.vhd)" - IDS_4126 "Dynamic-size VHD (.vhd)" - IDS_4127 "Differencing VHD (.vhd)" + IDS_4122 "Raw image (.img)" + IDS_4123 "HDI image (.hdi)" + IDS_4124 "HDX image (.hdx)" + IDS_4125 "Fixed-size VHD (.vhd)" + IDS_4126 "Dynamic-size VHD (.vhd)" + IDS_4127 "Differencing VHD (.vhd)" + IDS_4128 "Large blocks (2 MB)" + IDS_4129 "Small blocks (512 KB)" + IDS_4130 "VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0" + IDS_4131 "Select the parent VHD" + IDS_4132 "WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH!\n\nThis could indicate that the parent image was modified after this VHD was created.\n\nThis could also happen if the VHD files were moved/copied, or the differencing VHD was created with DiskPart.\n\nDo you wish to fix this error after a file copy or DiskPart creation?" + IDS_4133 "VHD Timestamp Mismatch" + IDS_4134 "Could not fix VHD timestamp." IDS_4352 "MFM/RLL" IDS_4353 "XTA" diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 7452aee2f..c93de28cb 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -2591,25 +2591,17 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM size = (tracks * hpc * spt) << 9; set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20LL)); hdconf_initialize_hdt_combo(hdlg); - - // TODO: Why is it crashing when I try to use string resources here? - // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4122)); - // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4123)); - // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4124)); - // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4125)); - // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4126)); - // settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4127)); - - settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Raw image (.img)"); - settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"HDI image (.hdi)"); - settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"HDX image (.hdx)"); - settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Fixed-size VHD (.vhd)"); - settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Dynamic-size VHD (.vhd)"); - settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, (LPARAM) L"Differencing VHD (.vhd)"); + + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4122)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4123)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4124)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4125)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4126)); + settings_add_string(hdlg, IDC_COMBO_HD_IMG_FORMAT, win_get_string(IDS_4127)); settings_set_cur_sel(hdlg, IDC_COMBO_HD_IMG_FORMAT, 0); - settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, (LPARAM) L"Large blocks (2 MB)"); - settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, (LPARAM) L"Small blocks (512 KB)"); + settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, win_get_string(IDS_4128)); + settings_add_string(hdlg, IDC_COMBO_HD_BLOCK_SIZE, win_get_string(IDS_4129)); settings_set_cur_sel(hdlg, IDC_COMBO_HD_BLOCK_SIZE, 0); settings_show_window(hdlg, IDC_COMBO_HD_BLOCK_SIZE, FALSE); @@ -2767,7 +2759,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM _86box_geometry = create_drive_vhd_dynamic(hd_file_name_multibyte, tracks, hpc, spt, block_size); break; case 5: - if (file_dlg_w(hdlg, L"VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0", L"", L"Select the parent VHD",0)) { + if (file_dlg_w(hdlg, plat_get_string(IDS_4130), L"", plat_get_string(IDS_4131), 0)) { return TRUE; } _86box_geometry = create_drive_vhd_diff(hd_file_name_multibyte, openfilestring, block_size); @@ -2887,16 +2879,11 @@ hdd_add_file_open_error: if (vhd == NULL) { settings_msgbox_header(MBX_ERROR, (existing & 1) ? (wchar_t *) IDS_4114 : (wchar_t *) IDS_4115, (existing & 1) ? (wchar_t *) IDS_4107 : (wchar_t *) IDS_4108); return TRUE; - } else if (vhd_error == MVHD_ERR_TIMESTAMP) { - wchar_t* ts_warning = - L"WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH!\n\n" - "This could indicate that the parent image was modified after this VHD was created.\n\n" - "This could also happen if the VHD files were moved/copied, or the differencing VHD was created with DiskPart.\n\n" - "Do you wish to fix this error after a file copy or DiskPart creation?"; - if (settings_msgbox_ex(MBX_QUESTION_YN, L"VHD Timestamp Mismatch", ts_warning, NULL, NULL, NULL) != 0) { + } else if (vhd_error == MVHD_ERR_TIMESTAMP) { + if (settings_msgbox_ex(MBX_QUESTION_YN, plat_get_string(IDS_4133), plat_get_string(IDS_4132), NULL, NULL, NULL) != 0) { int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhd_error); if (ts_res != 0) { - settings_msgbox_header(MBX_ERROR, L"Error", L"Could not fix VHD timestamp."); + settings_msgbox_header(MBX_ERROR, plat_get_string(IDS_2049), plat_get_string(IDS_4134)); mvhd_close(vhd); return TRUE; } From 21e555b63f913027a0f9b84a882068984a52bcaf Mon Sep 17 00:00:00 2001 From: Stephen McKinney Date: Thu, 19 Nov 2020 01:23:27 -0600 Subject: [PATCH 06/67] Update to latest MiniVHD. --- src/disk/minivhd/cwalk.c | 3 +++ src/disk/minivhd/minivhd_convert.c | 3 +++ src/disk/minivhd/minivhd_create.c | 3 +++ src/disk/minivhd/minivhd_io.c | 3 +++ src/disk/minivhd/minivhd_manage.c | 4 +++- src/disk/minivhd/minivhd_struct_rw.c | 4 +++- src/disk/minivhd/minivhd_struct_rw.h | 2 +- src/disk/minivhd/minivhd_util.c | 14 ++++++++++---- 8 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/disk/minivhd/cwalk.c b/src/disk/minivhd/cwalk.c index 265de0f72..f0c48427c 100644 --- a/src/disk/minivhd/cwalk.c +++ b/src/disk/minivhd/cwalk.c @@ -1,3 +1,6 @@ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif #include #include #include diff --git a/src/disk/minivhd/minivhd_convert.c b/src/disk/minivhd/minivhd_convert.c index 231e0f9b8..1de6f4613 100644 --- a/src/disk/minivhd/minivhd_convert.c +++ b/src/disk/minivhd/minivhd_convert.c @@ -1,3 +1,6 @@ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif #include #include #include diff --git a/src/disk/minivhd/minivhd_create.c b/src/disk/minivhd/minivhd_create.c index 9e34ece9d..c47c7d82d 100644 --- a/src/disk/minivhd/minivhd_create.c +++ b/src/disk/minivhd/minivhd_create.c @@ -1,3 +1,6 @@ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif #include #include #include diff --git a/src/disk/minivhd/minivhd_io.c b/src/disk/minivhd/minivhd_io.c index 8e9172e63..ddd17177e 100644 --- a/src/disk/minivhd/minivhd_io.c +++ b/src/disk/minivhd/minivhd_io.c @@ -3,6 +3,9 @@ * \brief Sector reading and writing implementations */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif #include #include #include "minivhd_internal.h" diff --git a/src/disk/minivhd/minivhd_manage.c b/src/disk/minivhd/minivhd_manage.c index 75e095332..e9473c0e3 100644 --- a/src/disk/minivhd/minivhd_manage.c +++ b/src/disk/minivhd/minivhd_manage.c @@ -2,7 +2,9 @@ * \file * \brief VHD management functions (open, close, read write etc) */ - +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif #include #include #include diff --git a/src/disk/minivhd/minivhd_struct_rw.c b/src/disk/minivhd/minivhd_struct_rw.c index 66f2289af..c77fa600a 100644 --- a/src/disk/minivhd/minivhd_struct_rw.c +++ b/src/disk/minivhd/minivhd_struct_rw.c @@ -2,7 +2,9 @@ * \file * \brief Header and footer serialize/deserialize functions */ - +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif #include #include #include diff --git a/src/disk/minivhd/minivhd_struct_rw.h b/src/disk/minivhd/minivhd_struct_rw.h index 0b1e0181f..ee49bb696 100644 --- a/src/disk/minivhd/minivhd_struct_rw.h +++ b/src/disk/minivhd/minivhd_struct_rw.h @@ -1,5 +1,5 @@ #ifndef MINIVHD_STRUCT_RW_H -#define minivhd_struct_rw +#define MINIVHD_STRUCT_RW_H #include "minivhd_internal.h" diff --git a/src/disk/minivhd/minivhd_util.c b/src/disk/minivhd/minivhd_util.c index d8f44cad0..5bfc59915 100644 --- a/src/disk/minivhd/minivhd_util.c +++ b/src/disk/minivhd/minivhd_util.c @@ -2,7 +2,9 @@ * \file * \brief Utility functions */ - +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif #include #include #include @@ -152,7 +154,7 @@ FILE* mvhd_fopen(const char* path, const char* mode, int* err) { } } #else - f = fopen64(path, mode); + f = fopen(path, mode); if (f == NULL) { mvhd_errno = errno; *err = MVHD_ERR_FILE; @@ -253,8 +255,10 @@ int64_t mvhd_ftello64(FILE* stream) { #ifdef _MSC_VER return _ftelli64(stream); -#else +#elif defined(__MINGW32__) return ftello64(stream); +#else /* This should work with linux (with _FILE_OFFSET_BITS), and hopefully OS X and BSD */ + return ftello(stream); #endif } @@ -262,8 +266,10 @@ int mvhd_fseeko64(FILE* stream, int64_t offset, int origin) { #ifdef _MSC_VER return _fseeki64(stream, offset, origin); -#else +#elif defined(__MINGW32__) return fseeko64(stream, offset, origin); +#else /* This should work with linux (with _FILE_OFFSET_BITS), and hopefully OS X and BSD */ + return fseeko(stream, offset, origin); #endif } From 5fe18cebf67b013e37a4fa853deba710463ebad3 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 19 Nov 2020 20:57:05 +0100 Subject: [PATCH 07/67] Ported the latest PCem banshee fixes. --- src/video/vid_voodoo_banshee.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index bbe86cb73..7a46dc860 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -178,6 +178,8 @@ enum #define VIDPROCCFG_CURSOR_MODE (1 << 1) #define VIDPROCCFG_HALF_MODE (1 << 4) #define VIDPROCCFG_OVERLAY_ENABLE (1 << 8) +#define VIDPROCCFG_OVERLAY_CLUT_BYPASS (1 << 11) +#define VIDPROCCFG_OVERLAY_CLUT_SEL (1 << 13) #define VIDPROCCFG_H_SCALE_ENABLE (1 << 14) #define VIDPROCCFG_V_SCALE_ENABLE (1 << 15) #define VIDPROCCFG_FILTER_MODE_MASK (3 << 16) @@ -1666,7 +1668,12 @@ void banshee_hwcursor_draw(svga_t *svga, int displine) int g = (data >> 5) & 0x3f; \ int b = data >> 11; \ \ - buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \ + buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ + else \ + buf[wp++] = (clut[r << 3] & 0x0000ff) | \ + (clut[g << 2] & 0x00ff00) | \ + (clut[b << 3] & 0xff0000); \ src += 2; \ } \ } while (0) @@ -1676,7 +1683,7 @@ void banshee_hwcursor_draw(svga_t *svga, int displine) { \ int c; \ int wp = 0; \ - uint32_t base_addr = buf ? src_addr2 : src_addr; \ + uint32_t base_addr = (buf == banshee->overlay_buffer[1]) ? src_addr2 : src_addr; \ \ for (c = 0; c < voodoo->overlay.overlay_bytes; c += 2) \ { \ @@ -1685,7 +1692,12 @@ void banshee_hwcursor_draw(svga_t *svga, int displine) int g = (data >> 5) & 0x3f; \ int b = data >> 11; \ \ - buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \ + buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ + else \ + buf[wp++] = (clut[r << 3] & 0x0000ff) | \ + (clut[g << 2] & 0x00ff00) | \ + (clut[b << 3] & 0xff0000); \ } \ } while (0) @@ -1953,6 +1965,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) uint32_t src_x = 0; unsigned int y_coeff = (voodoo->overlay.src_y & 0xfffff) >> 4; int skip_filtering; + uint32_t *clut = &svga->pallook[(banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_SEL) ? 256 : 0]; if (svga->render == svga_render_null && !svga->changedvram[src_addr >> 12] && !svga->changedvram[src_addr2 >> 12] && From ba16597d21611da161abdc4605d0de7d2d633dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Thu, 19 Nov 2020 23:22:46 +0100 Subject: [PATCH 08/67] Tweaks to the "save settings" dialog Changed the Cancel button to a regular button, as per the MS guidelines Also changed the caption for when invoked by the close button --- src/include/86box/language.h | 2 +- src/win/86Box.rc | 2 +- src/win/win_settings.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/include/86box/language.h b/src/include/86box/language.h index a16f2f0ac..46de31f5f 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -96,7 +96,7 @@ #define IDS_2120 2120 // "No ROMs found" #define IDS_2121 2121 // "Save changes\nThis will hard..." #define IDS_2122 2122 // "Discard changes\nAll changes..." -#define IDS_2123 2123 // "Cancel\nGo back to the..." +#define IDS_2123 2123 // "Do you want to save the settings?" #define IDS_2124 2124 // "About 86Box" #define IDS_2125 2125 // "86Box v" EMU_VERSION #define IDS_2126 2126 // "An emulator of old computers..." diff --git a/src/win/86Box.rc b/src/win/86Box.rc index d3529a82f..991e2df30 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -988,7 +988,7 @@ BEGIN IDS_2120 "No ROMs found" IDS_2121 "Save changes\nThis will hard reset the emulated machine." IDS_2122 "Discard changes\nAll changes made to the settings will be lost." - IDS_2123 "Cancel\nGo back to the Settings window." + IDS_2123 "Do you want to save the settings?" IDS_2124 "About 86Box" IDS_2125 "86Box v" EMU_VERSION IDS_2126 "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information." diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 8c08d9ae2..9c25aa178 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -495,7 +495,7 @@ win_settings_changed(void) static int -settings_msgbox_reset(void) +settings_msgbox_reset(int button) { int changed, i = 0; HWND h; @@ -506,7 +506,7 @@ settings_msgbox_reset(void) h = hwndMain; hwndMain = hwndParentDialog; - i = ui_msgbox_ex(MBX_QUESTION | MBX_LINKS, (wchar_t *) IDS_2051, NULL, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, (wchar_t *) IDS_2123); + i = ui_msgbox_ex(MBX_QUESTION | MBX_LINKS, (wchar_t *) (button ? IDS_2051 : IDS_2123), NULL, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, NULL); hwndMain = h; @@ -4622,7 +4622,7 @@ win_settings_confirm(HWND hdlg, int button) int i; SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); - i = settings_msgbox_reset(); + i = settings_msgbox_reset(button); if (i > 0) { if (i == 2) win_settings_save(); From ec5ab2ccf068eda392aca93612b335783bd08fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Thu, 19 Nov 2020 23:32:27 +0100 Subject: [PATCH 09/67] Use sentence case in dialogs --- src/win/86Box.rc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 991e2df30..9e5212a54 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -1021,9 +1021,9 @@ BEGIN IDS_2133 LIB_NAME_FLUIDSYNTH " is required for FluidSynth MIDI output." IDS_2134 "Entering fullscreen mode" IDS_2135 "Don't show this message again" - IDS_2136 "Don't Exit" + IDS_2136 "Don't exit" IDS_2137 "Reset" - IDS_2138 "Don't Reset" + IDS_2138 "Don't reset" IDS_2139 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" END @@ -1035,8 +1035,8 @@ BEGIN IDS_4099 "MFM/RLL or ESDI CD-ROM drives never existed" IDS_4100 "Custom..." IDS_4101 "Custom (large)..." - IDS_4102 "Add New Hard Disk" - IDS_4103 "Add Existing Hard Disk" + IDS_4102 "Add new hard disk" + IDS_4103 "Add existing hard disk" IDS_4104 "HDI disk images cannot be larger than 4 GB." IDS_4105 "Disk images cannot be larger than 127 GB." IDS_4106 "Hard disk images (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0All files (*.*)\0*.*\0" @@ -1054,7 +1054,7 @@ BEGIN IDS_4118 "The selected file will be overwritten. Are you sure you want to use it?" IDS_4119 "Unsupported disk image" IDS_4120 "Overwrite" - IDS_4121 "Don't Overwrite" + IDS_4121 "Don't overwrite" IDS_4352 "MFM/RLL" IDS_4353 "XTA" From cf8da1f58f7414f16dcca666a4c9f90e5725bda0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Thu, 19 Nov 2020 23:56:35 +0100 Subject: [PATCH 10/67] Fix video settings page taking ages to appear --- src/win/win_settings.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 9c25aa178..9175ff930 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -217,6 +217,17 @@ settings_listview_select(HWND hdlg, int id, int selection) } +static void +settings_process_messages() +{ + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + + static BOOL image_list_init(HWND hdlg, int id, const uint8_t *icon_ids) { @@ -1067,6 +1078,8 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) } c++; + + settings_process_messages(); } settings_enable_window(hdlg, IDC_COMBO_VIDEO, !(machines[temp_machine].flags & MACHINE_VIDEO_ONLY)); @@ -2606,10 +2619,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM fwrite(big_buf, 1, 1048576, f); SendMessage(h, PBM_SETPOS, (WPARAM) (i + 1), (LPARAM) 0); - while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } + settings_process_messages(); } } From 8504a00a00a2d5f281c2b444933c860ce2b2f3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Fri, 20 Nov 2020 00:26:06 +0100 Subject: [PATCH 11/67] Make the list views in settings prettier --- src/win/Makefile.mingw | 2 +- src/win/win_settings.c | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index d8d7ba9b8..de404565d 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -813,7 +813,7 @@ endif ifneq ($(WX), n) LIBS += $(WX_LIBS) -lm endif -LIBS += -lpng -lz -lwsock32 -lshell32 -liphlpapi -lpsapi -lSDL2 -limm32 -lhid -lsetupapi -loleaut32 -lversion -lwinmm -static -lstdc++ +LIBS += -lpng -lz -lwsock32 -lshell32 -liphlpapi -lpsapi -lSDL2 -limm32 -lhid -lsetupapi -loleaut32 -luxtheme -lversion -lwinmm -static -lstdc++ ifneq ($(X64), y) LIBS += -Wl,--large-address-aware endif diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 9175ff930..5b9124f4c 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -20,6 +20,7 @@ #define BITMAP WINDOWS_BITMAP #include #include +#include #undef BITMAP #ifdef ENABLE_SETTINGS_LOG #include @@ -207,6 +208,17 @@ settings_show_window(HWND hdlg, int id, int condition) } +static void +settings_listview_enable_styles(HWND hdlg, int id) +{ + HWND h; + + h = GetDlgItem(hdlg, id); + SetWindowTheme(h, L"Explorer", NULL); + ListView_SetExtendedListViewStyle(h, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); +} + + static void settings_listview_select(HWND hdlg, int id, int selection) { @@ -3124,6 +3136,8 @@ win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPar lv1_current_sel = -1; recalc_location_controls(hdlg, 0, 0); + settings_listview_enable_styles(hdlg, IDC_LIST_HARD_DISKS); + ignore_change = 0; return TRUE; @@ -4178,6 +4192,8 @@ win_settings_floppy_and_cdrom_drives_proc(HWND hdlg, UINT message, WPARAM wParam settings_set_check(hdlg, IDC_CHECKTURBO, temp_fdd_turbo[lv1_current_sel]); settings_set_check(hdlg, IDC_CHECKBPB, temp_fdd_check_bpb[lv1_current_sel]); + settings_listview_enable_styles(hdlg, IDC_LIST_FLOPPY_DRIVES); + lv2_current_sel = 0; win_settings_cdrom_drives_init_columns(hdlg); image_list_init(hdlg, IDC_LIST_CDROM_DRIVES, (const uint8_t *) cd_icons); @@ -4200,6 +4216,8 @@ win_settings_floppy_and_cdrom_drives_proc(HWND hdlg, UINT message, WPARAM wParam settings_set_cur_sel(hdlg, IDC_COMBO_CD_BUS, b); cdrom_recalc_location_controls(hdlg, 0); + settings_listview_enable_styles(hdlg, IDC_LIST_CDROM_DRIVES); + ignore_change = 0; return TRUE; @@ -4362,6 +4380,8 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam settings_set_cur_sel(hdlg, IDC_COMBO_MO_BUS, b); mo_recalc_location_controls(hdlg, 0); + settings_listview_enable_styles(hdlg, IDC_LIST_MO_DRIVES); + lv2_current_sel = 0; win_settings_zip_drives_init_columns(hdlg); image_list_init(hdlg, IDC_LIST_ZIP_DRIVES, (const uint8_t *) zip_icons); @@ -4384,6 +4404,8 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam settings_set_cur_sel(hdlg, IDC_COMBO_ZIP_BUS, b); zip_recalc_location_controls(hdlg, 0); + settings_listview_enable_styles(hdlg, IDC_LIST_ZIP_DRIVES); + ignore_change = 0; return TRUE; @@ -4669,6 +4691,7 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) image_list_init(hdlg, IDC_SETTINGSCATLIST, (const uint8_t *) cat_icons); win_settings_main_insert_categories(h); settings_listview_select(hdlg, IDC_SETTINGSCATLIST, first_cat); + settings_listview_enable_styles(hdlg, IDC_SETTINGSCATLIST); return TRUE; case WM_NOTIFY: if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_SETTINGSCATLIST)) { From ec38d21529699014bc2e5fe2e9bcd84feed658e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Fri, 20 Nov 2020 00:26:11 +0100 Subject: [PATCH 12/67] Fix warning --- src/win/win_settings.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 5b9124f4c..cfda94215 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -2462,7 +2462,6 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM uint8_t id = 0; wchar_t *twcs; vhd_footer_t *vft = NULL; - MSG msg; switch (message) { case WM_INITDIALOG: From c10fc05ea6fbab9ce56b0938fc7c294e5f0db8bc Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Nov 2020 01:28:36 +0100 Subject: [PATCH 13/67] Ported the CPU fixes from PCem. --- src/cpu/386.c | 10 +++++----- src/cpu/386_dynarec.c | 26 +++++++++++++------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/cpu/386.c b/src/cpu/386.c index fe05bb02e..940e01a76 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -281,11 +281,6 @@ exec386(int cycs) } } - ins_cycles -= cycles; - tsc += ins_cycles; - - cycdiff = oldcyc - cycles; - if (smi_line) enter_smm_check(0); else if (trap) { @@ -336,6 +331,11 @@ exec386(int cycs) cpu_end_block_after_ins = 0; + ins_cycles -= cycles; + tsc += ins_cycles; + + cycdiff = oldcyc - cycles; + if (timetolive) { timetolive--; if (!timetolive) diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 663770bc3..552669434 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -756,19 +756,6 @@ exec386_dynarec(int cycs) exec386_dynarec_dyn(); } - cycdiff = oldcyc - cycles; - delta = tsc - oldtsc; - if (delta > 0) { - /* TSC has changed, this means interim timer processing has happened, - see how much we still need to add. */ - cycdiff -= delta; - if (cycdiff > 0) - tsc += cycdiff; - } else { - /* TSC has not changed. */ - tsc += cycdiff; - } - if (cpu_state.abrt) { flags_rebuild(); tempi = cpu_state.abrt & ABRT_MASK; @@ -819,6 +806,19 @@ exec386_dynarec(int cycs) } } + cycdiff = oldcyc - cycles; + delta = tsc - oldtsc; + if (delta > 0) { + /* TSC has changed, this means interim timer processing has happened, + see how much we still need to add. */ + cycdiff -= delta; + if (cycdiff > 0) + tsc += cycdiff; + } else { + /* TSC has not changed. */ + tsc += cycdiff; + } + if (cycdiff > 0) { if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) timer_process_inline(); From 4dd15c5824333624b5c63583e4a513610ef88841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Fri, 20 Nov 2020 01:31:21 +0100 Subject: [PATCH 14/67] Enable multithreaded make for GH actions --- .github/workflows/c-cpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index b3a637010..277acdaee 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -34,5 +34,5 @@ jobs: install: 'make mingw-w64-i686-toolchain mingw-w64-i686-openal mingw-w64-i686-freetype mingw-w64-i686-SDL2 mingw-w64-i686-zlib mingw-w64-i686-libpng mingw-w64-i686-libvncserver' - uses: actions/checkout@v2 - name: make - run: make -fwin/makefile.mingw DEV_BUILD=${{ matrix.dev-build }} NEW_DYNAREC=${{ matrix.new-dynarec }} VNC=n + run: make -fwin/makefile.mingw -j DEV_BUILD=${{ matrix.dev-build }} NEW_DYNAREC=${{ matrix.new-dynarec }} VNC=n working-directory: ./src From e1e5ff563abbbb4e9bdee1f71665f8b2f64db1ed Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Nov 2020 02:57:15 +0100 Subject: [PATCH 15/67] Added MBX_WARNING flag to allow question dialogs with warning icon. --- src/include/86box/ui.h | 4 +++- src/win/win_dialog.c | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/include/86box/ui.h b/src/include/86box/ui.h index f497fb857..1c4c5aee1 100644 --- a/src/include/86box/ui.h +++ b/src/include/86box/ui.h @@ -34,7 +34,9 @@ extern "C" { #define MBX_ERROR 2 #define MBX_QUESTION 3 #define MBX_QUESTION_YN 4 -#define MBX_FATAL 0x20 +#define MBX_QMARK 0x10 +#define MBX_WARNING 0x20 +#define MBX_FATAL 0x40 #define MBX_ANSI 0x80 #define MBX_LINKS 0x100 #define MBX_DONTASK 0x200 diff --git a/src/win/win_dialog.c b/src/win/win_dialog.c index 16b1a2cc3..1e48b7d40 100644 --- a/src/win/win_dialog.c +++ b/src/win/win_dialog.c @@ -114,6 +114,9 @@ ui_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn2, voi else tdconfig.dwCommonButtons |= TDCBF_CANCEL_BUTTON; } + + if (flags & MBX_WARNING) + tdconfig.pszMainIcon = TD_WARNING_ICON; break; } From 637495fda1baf4c8b7d605d3e373d8142c780e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Fri, 20 Nov 2020 03:15:51 +0100 Subject: [PATCH 16/67] Made the mismatched differencing VHD more generic --- src/win/86Box.rc | 8 ++++---- src/win/win_settings.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 3d3eafdf3..ef9951f36 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -1041,8 +1041,8 @@ BEGIN IDS_4099 "MFM/RLL or ESDI CD-ROM drives never existed" IDS_4100 "Custom..." IDS_4101 "Custom (large)..." - IDS_4102 "Add new hard disk" - IDS_4103 "Add existing hard disk" + IDS_4102 "Add New Hard Disk" + IDS_4103 "Add Existing Hard Disk" IDS_4104 "HDI disk images cannot be larger than 4 GB." IDS_4105 "Disk images cannot be larger than 127 GB." IDS_4106 "Hard disk images (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0All files (*.*)\0*.*\0" @@ -1071,8 +1071,8 @@ BEGIN IDS_4129 "Small blocks (512 KB)" IDS_4130 "VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0" IDS_4131 "Select the parent VHD" - IDS_4132 "WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH!\n\nThis could indicate that the parent image was modified after this VHD was created.\n\nThis could also happen if the VHD files were moved/copied, or the differencing VHD was created with DiskPart.\n\nDo you wish to fix this error after a file copy or DiskPart creation?" - IDS_4133 "VHD Timestamp Mismatch" + IDS_4132 "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" + IDS_4133 "Parent and child disk timestamps do not match" IDS_4134 "Could not fix VHD timestamp." IDS_4352 "MFM/RLL" diff --git a/src/win/win_settings.c b/src/win/win_settings.c index fe435803f..2d7c5b0b1 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -2931,7 +2931,7 @@ hdd_add_file_open_error: settings_msgbox_header(MBX_ERROR, (existing & 1) ? (wchar_t *) IDS_4114 : (wchar_t *) IDS_4115, (existing & 1) ? (wchar_t *) IDS_4107 : (wchar_t *) IDS_4108); return TRUE; } else if (vhd_error == MVHD_ERR_TIMESTAMP) { - if (settings_msgbox_ex(MBX_QUESTION_YN, plat_get_string(IDS_4133), plat_get_string(IDS_4132), NULL, NULL, NULL) != 0) { + if (settings_msgbox_ex(MBX_QUESTIONYN | MBX_WARNING, plat_get_string(IDS_4133), plat_get_string(IDS_4132), NULL, NULL, NULL) != 0) { int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhd_error); if (ts_res != 0) { settings_msgbox_header(MBX_ERROR, plat_get_string(IDS_2049), plat_get_string(IDS_4134)); From 376a904c1b17433158dd728ad3563ffd5adede7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Fri, 20 Nov 2020 03:21:32 +0100 Subject: [PATCH 17/67] Fix build --- src/win/win_settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 2d7c5b0b1..183b9920f 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -2931,7 +2931,7 @@ hdd_add_file_open_error: settings_msgbox_header(MBX_ERROR, (existing & 1) ? (wchar_t *) IDS_4114 : (wchar_t *) IDS_4115, (existing & 1) ? (wchar_t *) IDS_4107 : (wchar_t *) IDS_4108); return TRUE; } else if (vhd_error == MVHD_ERR_TIMESTAMP) { - if (settings_msgbox_ex(MBX_QUESTIONYN | MBX_WARNING, plat_get_string(IDS_4133), plat_get_string(IDS_4132), NULL, NULL, NULL) != 0) { + if (settings_msgbox_ex(MBX_QUESTION_YN | MBX_WARNING, plat_get_string(IDS_4133), plat_get_string(IDS_4132), NULL, NULL, NULL) != 0) { int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhd_error); if (ts_res != 0) { settings_msgbox_header(MBX_ERROR, plat_get_string(IDS_2049), plat_get_string(IDS_4134)); From e492ca52d3ccc114d4c953f5409d2cb442b67a22 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 20 Nov 2020 05:41:06 +0100 Subject: [PATCH 18/67] Eliminated s3->busy completely, fixes S3 928 drivers without FIFO under NT 3.1 while keeping everything else intact. Moved the DC390 timer initialization to the Flush write command, where it takes a higher priority, fixes NT 3.1 DC390 specific drivers while keeping the AMD branded drivers intact. --- src/scsi/scsi_pcscsi.c | 2 +- src/video/vid_s3.c | 21 +-------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/src/scsi/scsi_pcscsi.c b/src/scsi/scsi_pcscsi.c index 22c78818b..d55528c6e 100644 --- a/src/scsi/scsi_pcscsi.c +++ b/src/scsi/scsi_pcscsi.c @@ -595,7 +595,6 @@ handle_satn_stop(void *priv) dev->rregs[ESP_RSEQ] = SEQ_CD; esp_log("ESP SCSI Command len = %d, raising IRQ\n", dev->cmdlen); esp_raise_irq(dev); - timer_on_auto(&dev->timer, 10.0); } } @@ -729,6 +728,7 @@ esp_reg_write(esp_t *dev, uint32_t saddr, uint32_t val) dev->rregs[ESP_RINTR] = INTR_FC; dev->rregs[ESP_RSEQ] = 0; dev->rregs[ESP_RFLAGS] = 0; + timer_on_auto(&dev->timer, 10.0); break; case CMD_RESET: esp_pci_soft_reset(dev); diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 704d193ae..a134ccee3 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -2676,7 +2676,7 @@ s3_accel_in(uint16_t port, void *p) if (FIFO_FULL && s3->chip >= S3_VISION964) temp |= 0xf8; /*FIFO full*/ } else { - if (s3->busy || s3->force_busy) { + if (s3->force_busy) { temp |= 0x02; /*Hardware busy*/ } s3->force_busy = 0; @@ -3314,10 +3314,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ dstbase >>= 2; } - if (((s3_cpu_src(s3) || s3_cpu_dest(s3))) && (s3->chip >= S3_86C928 && s3->chip < S3_TRIO64V)) { - s3->busy = 1; - } - if ((s3->accel.cmd & 0x100) && (s3_cpu_src(s3) || s3_cpu_dest(s3)) && !cpu_input) { s3->force_busy = 1; } @@ -3410,7 +3406,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ if (s3->bpp == 0) cpu_dat >>= 8; else cpu_dat >>= 16; if (!s3->accel.sy) { - s3->busy = 0; break; } @@ -3481,7 +3476,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ else cpu_dat >>= 16; if (!s3->accel.sy) { - s3->busy = 0; break; } @@ -3653,10 +3647,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.dest = dstbase + s3->accel.cy * s3->width; s3->accel.sy--; - if (s3->accel.sy < 0) { - s3->busy = 0; - } - if (cpu_input) { if (s3_cpu_dest(s3)) s3->data_available = 1; @@ -3737,7 +3727,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.sy--; if (s3->accel.sy < 0) { - s3->busy = 0; return; } } @@ -3825,9 +3814,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.sy--; - if (s3->accel.sy < 0) - s3->busy = 0; - if (cpu_input) return; @@ -3950,9 +3936,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.sy--; - if (s3->accel.sy < 0) - s3->busy = 0; - if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; if (s3->accel.sy < 0) return; @@ -4032,7 +4015,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; } - s3->busy = 0; break; case 11: /*Polygon Fill Pattern (Trio64 only)*/ @@ -4121,7 +4103,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; } - s3->busy = 0; break; } } From 7d2834b2019b781ab04bb68545acb82231aced7c Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Nov 2020 05:42:47 +0100 Subject: [PATCH 19/67] More Settings dialog fixes and improvements. --- src/include/86box/language.h | 7 +- src/include/86box/resource.h | 204 +++++++++--------- src/include/86box/win.h | 3 +- src/win/86Box.rc | 187 ++++++++-------- src/win/icons/storage_controllers.ico | Bin 0 -> 1150 bytes src/win/win_media_menu.c | 2 +- src/win/win_settings.c | 294 ++++++++++++++++---------- 7 files changed, 395 insertions(+), 302 deletions(-) create mode 100644 src/win/icons/storage_controllers.ico diff --git a/src/include/86box/language.h b/src/include/86box/language.h index af7b6a5bc..451811964 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -44,11 +44,11 @@ #define IDS_2068 2068 // "Sound" #define IDS_2069 2069 // "Network" #define IDS_2070 2070 // "Ports (COM & LPT)" -#define IDS_2071 2071 // "Other peripherals" +#define IDS_2071 2071 // "Storage controllers" #define IDS_2072 2072 // "Hard disks" #define IDS_2073 2073 // "Floppy and CD-ROM drives" #define IDS_2074 2074 // "Other removable devices" -#define IDS_2075 2075 // "CD-ROM images (*.ISO;*.CU.." +#define IDS_2075 2075 // "Other peripherals" #define IDS_2076 2076 // "Surface-based images (*.8.." #define IDS_2077 2077 // "Click to capture mouse" #define IDS_2078 2078 // "Press F12-F8 to release mouse" @@ -113,6 +113,7 @@ #define IDS_2137 2137 // "Reset" #define IDS_2138 2138 // "Don't Reset" #define IDS_2139 2139 // "MO images (*.IM?)\0*.IM?..." +#define IDS_2140 2140 // "CD-ROM images (*.ISO;*.CU.." #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -220,7 +221,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 92 +#define STR_NUM_2048 93 #define STR_NUM_3072 11 #define STR_NUM_4096 39 #define STR_NUM_4352 6 diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index 25c087fda..5b0cbf0c8 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -35,11 +35,12 @@ #define DLG_CFG_SOUND 114 /* sub-dialog of config */ #define DLG_CFG_NETWORK 115 /* sub-dialog of config */ #define DLG_CFG_PORTS 116 /* sub-dialog of config */ -#define DLG_CFG_PERIPHERALS 117 /* sub-dialog of config */ +#define DLG_CFG_STORAGE 117 /* sub-dialog of config */ #define DLG_CFG_HARD_DISKS 118 /* sub-dialog of config */ #define DLG_CFG_HARD_DISKS_ADD 119 /* sub-dialog of config */ #define DLG_CFG_FLOPPY_AND_CDROM_DRIVES 120 /* sub-dialog of config */ #define DLG_CFG_OTHER_REMOVABLE_DEVICES 121 /* sub-dialog of config */ +#define DLG_CFG_PERIPHERALS 122 /* sub-dialog of config */ /* Static text label IDs. */ #define IDT_1700 1700 /* Language: */ @@ -139,116 +140,117 @@ #define IDC_MEMSPIN 1019 #define IDC_TEXT_MB IDT_1705 -#define IDC_VIDEO 1030 /* video config */ -#define IDC_COMBO_VIDEO 1031 -#define IDC_CHECK_VOODOO 1032 -#define IDC_BUTTON_VOODOO 1033 +#define IDC_VIDEO 1020 /* video config */ +#define IDC_COMBO_VIDEO 1021 +#define IDC_CHECK_VOODOO 1022 +#define IDC_BUTTON_VOODOO 1023 -#define IDC_INPUT 1050 /* input config */ -#define IDC_COMBO_MOUSE 1051 -#define IDC_COMBO_JOYSTICK 1052 -#define IDC_COMBO_JOY 1053 -#define IDC_CONFIGURE_MOUSE 1054 +#define IDC_INPUT 1030 /* input config */ +#define IDC_COMBO_MOUSE 1031 +#define IDC_COMBO_JOYSTICK 1032 +#define IDC_COMBO_JOY 1033 +#define IDC_CONFIGURE_MOUSE 1034 -#define IDC_SOUND 1070 /* sound config */ -#define IDC_COMBO_SOUND 1071 -#define IDC_CHECK_SSI 1072 -#define IDC_CHECK_CMS 1073 -#define IDC_CHECK_GUS 1074 -#define IDC_COMBO_MIDI 1075 -#define IDC_CHECK_MPU401 1076 -#define IDC_CONFIGURE_MPU401 1077 -#define IDC_CHECK_FLOAT 1078 -#define IDC_CONFIGURE_GUS 1079 -#define IDC_COMBO_MIDI_IN 1080 +#define IDC_SOUND 1040 /* sound config */ +#define IDC_COMBO_SOUND 1041 +#define IDC_CHECK_SSI 1042 +#define IDC_CHECK_CMS 1043 +#define IDC_CHECK_GUS 1044 +#define IDC_COMBO_MIDI 1045 +#define IDC_CHECK_MPU401 1046 +#define IDC_CONFIGURE_MPU401 1047 +#define IDC_CHECK_FLOAT 1048 +#define IDC_CONFIGURE_GUS 1049 +#define IDC_COMBO_MIDI_IN 1050 -#define IDC_COMBO_NET_TYPE 1090 /* network config */ -#define IDC_COMBO_PCAP 1091 -#define IDC_COMBO_NET 1092 +#define IDC_COMBO_NET_TYPE 1060 /* network config */ +#define IDC_COMBO_PCAP 1061 +#define IDC_COMBO_NET 1062 -#define IDC_COMBO_LPT1 1110 /* ports config */ -#define IDC_COMBO_LPT2 1111 -#define IDC_COMBO_LPT3 1112 -#define IDC_CHECK_SERIAL1 1113 -#define IDC_CHECK_SERIAL2 1114 -#define IDC_CHECK_SERIAL3 1115 -#define IDC_CHECK_SERIAL4 1116 -#define IDC_CHECK_PARALLEL1 1117 -#define IDC_CHECK_PARALLEL2 1118 -#define IDC_CHECK_PARALLEL3 1119 +#define IDC_COMBO_LPT1 1070 /* ports config */ +#define IDC_COMBO_LPT2 1071 +#define IDC_COMBO_LPT3 1072 +#define IDC_CHECK_SERIAL1 1073 +#define IDC_CHECK_SERIAL2 1074 +#define IDC_CHECK_SERIAL3 1075 +#define IDC_CHECK_SERIAL4 1076 +#define IDC_CHECK_PARALLEL1 1077 +#define IDC_CHECK_PARALLEL2 1078 +#define IDC_CHECK_PARALLEL3 1079 -#define IDC_OTHER_PERIPH 1120 /* other periph config */ -#define IDC_COMBO_SCSI 1121 -#define IDC_CONFIGURE_SCSI 1122 -#define IDC_COMBO_HDC 1123 -#define IDC_CONFIGURE_HDC 1124 -#define IDC_CHECK_IDE_TER 1125 -#define IDC_BUTTON_IDE_TER 1126 -#define IDC_CHECK_IDE_QUA 1127 -#define IDC_BUTTON_IDE_QUA 1128 -#define IDC_CHECK_BUGGER 1129 -#define IDC_CHECK_POSTCARD 1130 -#define IDC_COMBO_ISARTC 1131 -#define IDC_CONFIGURE_ISARTC 1132 -#define IDC_COMBO_FDC 1133 -#define IDC_CONFIGURE_FDC 1134 -#define IDC_GROUP_ISAMEM 1140 -#define IDC_COMBO_ISAMEM_1 1141 -#define IDC_COMBO_ISAMEM_2 1142 -#define IDC_COMBO_ISAMEM_3 1143 -#define IDC_COMBO_ISAMEM_4 1144 -#define IDC_CONFIGURE_ISAMEM_1 1145 -#define IDC_CONFIGURE_ISAMEM_2 1146 -#define IDC_CONFIGURE_ISAMEM_3 1147 -#define IDC_CONFIGURE_ISAMEM_4 1148 +#define IDC_OTHER_PERIPH 1080 /* storage controllers config */ +#define IDC_COMBO_SCSI 1081 +#define IDC_CONFIGURE_SCSI 1082 +#define IDC_COMBO_HDC 1083 +#define IDC_CONFIGURE_HDC 1084 +#define IDC_CHECK_IDE_TER 1085 +#define IDC_BUTTON_IDE_TER 1086 +#define IDC_CHECK_IDE_QUA 1087 +#define IDC_BUTTON_IDE_QUA 1088 -#define IDC_HARD_DISKS 1150 /* hard disks config */ -#define IDC_LIST_HARD_DISKS 1151 -#define IDC_BUTTON_HDD_ADD_NEW 1152 -#define IDC_BUTTON_HDD_ADD 1153 -#define IDC_BUTTON_HDD_REMOVE 1154 -#define IDC_COMBO_HD_BUS 1155 -#define IDC_COMBO_HD_CHANNEL 1156 -#define IDC_COMBO_HD_ID 1157 -#define IDC_COMBO_HD_LUN 1158 -#define IDC_COMBO_HD_CHANNEL_IDE 1159 +#define IDC_HARD_DISKS 1090 /* hard disks config */ +#define IDC_LIST_HARD_DISKS 1091 +#define IDC_BUTTON_HDD_ADD_NEW 1092 +#define IDC_BUTTON_HDD_ADD 1093 +#define IDC_BUTTON_HDD_REMOVE 1094 +#define IDC_COMBO_HD_BUS 1095 +#define IDC_COMBO_HD_CHANNEL 1096 +#define IDC_COMBO_HD_ID 1097 +#define IDC_COMBO_HD_LUN 1098 +#define IDC_COMBO_HD_CHANNEL_IDE 1099 -#define IDC_EDIT_HD_FILE_NAME 1160 /* add hard disk dialog */ -#define IDC_EDIT_HD_SPT 1161 -#define IDC_EDIT_HD_HPC 1162 -#define IDC_EDIT_HD_CYL 1163 -#define IDC_EDIT_HD_SIZE 1164 -#define IDC_COMBO_HD_TYPE 1165 -#define IDC_PBAR_IMG_CREATE 1166 -#define IDC_COMBO_HD_IMG_FORMAT 1167 -#define IDC_COMBO_HD_BLOCK_SIZE 1168 +#define IDC_EDIT_HD_FILE_NAME 1100 /* add hard disk dialog */ +#define IDC_EDIT_HD_SPT 1101 +#define IDC_EDIT_HD_HPC 1102 +#define IDC_EDIT_HD_CYL 1103 +#define IDC_EDIT_HD_SIZE 1104 +#define IDC_COMBO_HD_TYPE 1105 +#define IDC_PBAR_IMG_CREATE 1106 +#define IDC_COMBO_HD_IMG_FORMAT 1107 +#define IDC_COMBO_HD_BLOCK_SIZE 1108 -#define IDC_REMOV_DEVICES 1170 /* floppy and cd-rom drives config */ -#define IDC_LIST_FLOPPY_DRIVES 1171 -#define IDC_COMBO_FD_TYPE 1172 -#define IDC_CHECKTURBO 1173 -#define IDC_CHECKBPB 1174 -#define IDC_LIST_CDROM_DRIVES 1175 -#define IDC_COMBO_CD_BUS 1176 -#define IDC_COMBO_CD_ID 1177 -#define IDC_COMBO_CD_LUN 1178 -#define IDC_COMBO_CD_CHANNEL_IDE 1179 +#define IDC_REMOV_DEVICES 1110 /* floppy and cd-rom drives config */ +#define IDC_LIST_FLOPPY_DRIVES 1111 +#define IDC_COMBO_FD_TYPE 1112 +#define IDC_CHECKTURBO 1113 +#define IDC_CHECKBPB 1114 +#define IDC_LIST_CDROM_DRIVES 1115 +#define IDC_COMBO_CD_BUS 1116 +#define IDC_COMBO_CD_ID 1117 +#define IDC_COMBO_CD_LUN 1118 +#define IDC_COMBO_CD_CHANNEL_IDE 1119 -#define IDC_LIST_ZIP_DRIVES 1180 /* other removable devices config */ -#define IDC_COMBO_ZIP_BUS 1181 -#define IDC_COMBO_ZIP_ID 1182 -#define IDC_COMBO_ZIP_LUN 1183 -#define IDC_COMBO_ZIP_CHANNEL_IDE 1184 -#define IDC_CHECK250 1185 -#define IDC_COMBO_CD_SPEED 1186 -#define IDC_LIST_MO_DRIVES 1187 -#define IDC_COMBO_MO_BUS 1188 -#define IDC_COMBO_MO_ID 1189 -#define IDC_COMBO_MO_LUN 1190 -#define IDC_COMBO_MO_CHANNEL_IDE 1191 -#define IDC_COMBO_MO_TYPE 1192 +#define IDC_LIST_ZIP_DRIVES 1120 /* other removable devices config */ +#define IDC_COMBO_ZIP_BUS 1121 +#define IDC_COMBO_ZIP_ID 1122 +#define IDC_COMBO_ZIP_LUN 1123 +#define IDC_COMBO_ZIP_CHANNEL_IDE 1124 +#define IDC_CHECK250 1125 +#define IDC_COMBO_CD_SPEED 1126 +#define IDC_LIST_MO_DRIVES 1127 +#define IDC_COMBO_MO_BUS 1128 +#define IDC_COMBO_MO_ID 1129 +#define IDC_COMBO_MO_LUN 1130 +#define IDC_COMBO_MO_CHANNEL_IDE 1131 +#define IDC_COMBO_MO_TYPE 1132 -#define IDC_SLIDER_GAIN 1193 /* sound gain dialog */ +#define IDC_CHECK_BUGGER 1140 /* other periph config */ +#define IDC_CHECK_POSTCARD 1141 +#define IDC_COMBO_ISARTC 1142 +#define IDC_CONFIGURE_ISARTC 1143 +#define IDC_COMBO_FDC 1144 +#define IDC_CONFIGURE_FDC 1145 +#define IDC_GROUP_ISAMEM 1146 +#define IDC_COMBO_ISAMEM_1 1147 +#define IDC_COMBO_ISAMEM_2 1148 +#define IDC_COMBO_ISAMEM_3 1149 +#define IDC_COMBO_ISAMEM_4 1150 +#define IDC_CONFIGURE_ISAMEM_1 1151 +#define IDC_CONFIGURE_ISAMEM_2 1152 +#define IDC_CONFIGURE_ISAMEM_3 1153 +#define IDC_CONFIGURE_ISAMEM_4 1154 + +#define IDC_SLIDER_GAIN 1160 /* sound gain dialog */ #define IDC_EDIT_FILE_NAME 1200 /* new floppy image dialog */ #define IDC_COMBO_DISK_SIZE 1201 diff --git a/src/include/86box/win.h b/src/include/86box/win.h index aae82adac..75c250ddb 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -177,10 +177,11 @@ extern void NewFloppyDialogCreate(HWND hwnd, int id, int part); #define SETTINGS_PAGE_SOUND 3 #define SETTINGS_PAGE_NETWORK 4 #define SETTINGS_PAGE_PORTS 5 -#define SETTINGS_PAGE_PERIPHERALS 6 +#define SETTINGS_PAGE_STORAGE 6 #define SETTINGS_PAGE_HARD_DISKS 7 #define SETTINGS_PAGE_FLOPPY_AND_CDROM_DRIVES 8 #define SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES 9 +#define SETTINGS_PAGE_PERIPHERALS 10 extern void win_settings_open(HWND hwnd); extern void win_settings_open_ex(HWND hwnd, int category); diff --git a/src/win/86Box.rc b/src/win/86Box.rc index ef9951f36..c0bb24bc8 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -324,7 +324,7 @@ FONT 9, "Segoe UI" BEGIN DEFPUSHBUTTON "OK",IDOK,246,235,50,14 PUSHBUTTON "Cancel",IDCANCEL,307,235,50,14 - CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_LIST | + CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 /* Leave this commented out until we get into localization. */ @@ -335,45 +335,45 @@ BEGIN #endif END -DLG_CFG_MACHINE DIALOG DISCARDABLE 107, 0, 305, 199 +DLG_CFG_MACHINE DIALOG DISCARDABLE 107, 0, 305, 200 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN COMBOBOX IDC_COMBO_MACHINE_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Machine type:",IDT_1708,7,8,60,10 + LTEXT "Machine type:",IDT_1708,7,9,60,10 COMBOBOX IDC_COMBO_MACHINE,71,26,138,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Machine:",IDT_1701,7,27,60,10 + LTEXT "Machine:",IDT_1701,7,28,60,10 PUSHBUTTON "Configure",IDC_CONFIGURE_MACHINE,214,26,46,12 - COMBOBOX IDC_COMBO_CPU_TYPE,71,44,110,120,CBS_DROPDOWNLIST | + COMBOBOX IDC_COMBO_CPU_TYPE,71,45,110,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "CPU type:",IDT_1702,7,45,59,10 - COMBOBOX IDC_COMBO_CPU,215,44,45,120,CBS_DROPDOWNLIST | + LTEXT "CPU type:",IDT_1702,7,47,59,10 + COMBOBOX IDC_COMBO_CPU,215,45,45,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Speed:",IDT_1704,189,45,24,10 - COMBOBOX IDC_COMBO_FPU,71,63,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + LTEXT "Speed:",IDT_1704,189,47,24,10 + COMBOBOX IDC_COMBO_FPU,71,64,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "FPU:",IDT_1707,7,63,59,10 - COMBOBOX IDC_COMBO_WS,71,82,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + LTEXT "FPU:",IDT_1707,7,66,59,10 + COMBOBOX IDC_COMBO_WS,71,83,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Wait states:",IDT_1703,7,83,60,10 - EDITTEXT IDC_MEMTEXT,70,101,45,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "Wait states:",IDT_1703,7,85,60,10 + EDITTEXT IDC_MEMTEXT,70,102,45,12,ES_AUTOHSCROLL | ES_NUMBER CONTROL "",IDC_MEMSPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,101, 12,12 - LTEXT "MB",IDT_1705,123,102,10,10 - LTEXT "Memory:",IDT_1706,7,102,30,10 - GROUPBOX "Time synchronization",IDC_TIME_SYNC,7,134,100,56 + LTEXT "MB",IDT_1705,123,104,10,10 + LTEXT "Memory:",IDT_1706,7,104,30,10 + GROUPBOX "Time synchronization",IDC_TIME_SYNC,7,135,100,56 CONTROL "Disabled",IDC_RADIO_TS_DISABLED,"Button", - BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,146,84,10 + BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,147,84,10 CONTROL "Enabled (local time)", IDC_RADIO_TS_LOCAL,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,14,160,84,10 + BS_AUTORADIOBUTTON | WS_TABSTOP,14,161,84,10 CONTROL "Enabled (UTC)", IDC_RADIO_TS_UTC,"Button", - BS_AUTORADIOBUTTON | WS_TABSTOP,14,174,84,10 + BS_AUTORADIOBUTTON | WS_TABSTOP,14,175,84,10 #ifdef USE_DYNAREC CONTROL "Dynamic Recompiler",IDC_CHECK_DYNAREC,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,119,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,120,94,10 #endif END @@ -381,7 +381,7 @@ DLG_CFG_VIDEO DIALOG DISCARDABLE 107, 0, 267, 45 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "Video:",IDT_1707,7,8,48,10 + LTEXT "Video:",IDT_1707,7,9,48,10 COMBOBOX IDC_COMBO_VIDEO,64,7,155,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Configure",IDC_CONFIGURE_VID,222,7,38,12 @@ -394,11 +394,11 @@ DLG_CFG_INPUT DIALOG DISCARDABLE 107, 0, 267, 65 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "Mouse :",IDT_1709,7,8,57,10 + LTEXT "Mouse :",IDT_1709,7,9,57,10 COMBOBOX IDC_COMBO_MOUSE,71,7,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Configure",IDC_CONFIGURE_MOUSE,214,7,46,12 - LTEXT "Joystick :",IDT_1710,7,26,58,10 + LTEXT "Joystick :",IDT_1710,7,27,58,10 COMBOBOX IDC_COMBO_JOYSTICK,71,25,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Joystick 1...",IDC_JOY1,7,44,50,14 @@ -407,73 +407,73 @@ BEGIN PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 END -DLG_CFG_SOUND DIALOG DISCARDABLE 107, 0, 267, 199 +DLG_CFG_SOUND DIALOG DISCARDABLE 107, 0, 267, 201 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN COMBOBOX IDC_COMBO_SOUND,71,7,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Sound card:",IDT_1711,7,8,59,10 + LTEXT "Sound card:",IDT_1711,7,9,59,10 PUSHBUTTON "Configure",IDC_CONFIGURE_SND,214,7,46,12 - COMBOBOX IDC_COMBO_MIDI,71,25,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + COMBOBOX IDC_COMBO_MIDI,71,26,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "MIDI Out Device:",IDT_1712,7,26,59,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI,214,25,46,12 + LTEXT "MIDI Out Device:",IDT_1712,7,28,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI,214,26,46,12 - COMBOBOX IDC_COMBO_MIDI_IN,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + COMBOBOX IDC_COMBO_MIDI_IN,71,45,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "MIDI In Device:",IDT_1713,7,44,59,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI_IN,214,43,46,12 + LTEXT "MIDI In Device:",IDT_1713,7,47,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI_IN,214,45,46,12 CONTROL "Standalone MPU-401",IDC_CHECK_MPU401,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,65,199,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,66,199,10 PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,64,46,12 CONTROL "Innovation SSI-2001",IDC_CHECK_SSI,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,83,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,84,95,10 CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,83,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,147,84,95,10 CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_GUS,214,99,46,12 + BS_AUTOCHECKBOX | WS_TABSTOP,7,101,94,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_GUS,214,101,46,12 CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,115,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,117,94,10 END -DLG_CFG_NETWORK DIALOG DISCARDABLE 107, 0, 267, 63 +DLG_CFG_NETWORK DIALOG DISCARDABLE 107, 0, 267, 65 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "Network type:",IDT_1714,7,8,59,10 + LTEXT "Network type:",IDT_1714,7,9,59,10 COMBOBOX IDC_COMBO_NET_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "PCap device:",IDT_1715,7,26,59,10 - COMBOBOX IDC_COMBO_PCAP,71,25,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + LTEXT "PCap device:",IDT_1715,7,28,59,10 + COMBOBOX IDC_COMBO_PCAP,71,26,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Network adapter:",IDT_1716,7,44,59,10 - COMBOBOX IDC_COMBO_NET,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + LTEXT "Network adapter:",IDT_1716,7,47,59,10 + COMBOBOX IDC_COMBO_NET,71,45,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,43,46,12 + PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,44,46,12 END DLG_CFG_PORTS DIALOG DISCARDABLE 107, 0, 267, 135 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "LPT1 Device:",IDT_1717,7,8,61,10 + LTEXT "LPT1 Device:",IDT_1717,7,9,61,10 COMBOBOX IDC_COMBO_LPT1,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LPT2 Device:",IDT_1718,7,27,61,10 + LTEXT "LPT2 Device:",IDT_1718,7,28,61,10 COMBOBOX IDC_COMBO_LPT2,71,26,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LPT3 Device:",IDT_1719,7,46,61,10 + LTEXT "LPT3 Device:",IDT_1719,7,47,61,10 COMBOBOX IDC_COMBO_LPT3,71,45,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP @@ -494,61 +494,32 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,7,118,94,10 END -DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 107, 0, 267, 220 +DLG_CFG_STORAGE DIALOG DISCARDABLE 107, 0, 267, 111 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "SCSI Controller:",IDT_1717,7,8,48,10 + LTEXT "SCSI Controller:",IDT_1717,7,9,48,10 COMBOBOX IDC_COMBO_SCSI,64,7,155,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI,222,7,38,12 - LTEXT "HD Controller:",IDT_1718,7,26,48,10 - COMBOBOX IDC_COMBO_HDC,64,25,155,120,CBS_DROPDOWNLIST | + LTEXT "HD Controller:",IDT_1718,7,28,48,10 + COMBOBOX IDC_COMBO_HDC,64,26,155,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,222,25,38,12 + PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,222,26,38,12 - LTEXT "FD Controller:",IDT_1768,7,44,48,10 - COMBOBOX IDC_COMBO_FDC,64,43,155,120,CBS_DROPDOWNLIST | + LTEXT "FD Controller:",IDT_1768,7,47,48,10 + COMBOBOX IDC_COMBO_FDC,64,45,155,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_FDC,222,43,38,12 + PUSHBUTTON "Configure",IDC_CONFIGURE_FDC,222,45,38,12 CONTROL "Tertiary IDE Controller",IDC_CHECK_IDE_TER,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,62,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_IDE_TER,222,61,38,12 + BS_AUTOCHECKBOX | WS_TABSTOP,7,66,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_TER,222,64,38,12 CONTROL "Quaternary IDE Controller",IDC_CHECK_IDE_QUA,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,80,199,10 - PUSHBUTTON "Configure",IDC_BUTTON_IDE_QUA,222,79,38,12 - - CONTROL "ISABugger device",IDC_CHECK_BUGGER,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,98,94,10 - - CONTROL "POST card",IDC_CHECK_POSTCARD,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,98,94,10 - - LTEXT "ISA RTC",IDT_1767,7,117,48,10 - COMBOBOX IDC_COMBO_ISARTC,64,116,155,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISARTC,222,116,38,12 - - GROUPBOX "ISA Memory Expansion",IDC_GROUP_ISAMEM,7,136,255,70 - LTEXT "#1:",IDT_1763,12,148,21,10 - COMBOBOX IDC_COMBO_ISAMEM_1,25,147,190,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_1,217,147,38,12 - LTEXT "#2:",IDT_1764,12,162,21,10 - COMBOBOX IDC_COMBO_ISAMEM_2,25,161,190,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_2,217,161,38,12 - LTEXT "#3:",IDT_1765,12,176,21,10 - COMBOBOX IDC_COMBO_ISAMEM_3,25,175,190,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_3,217,175,38,12 - LTEXT "#4:",IDT_1766,12,190,21,10 - COMBOBOX IDC_COMBO_ISAMEM_4,25,189,190,120, - CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_4,217,189,38,12 + BS_AUTOCHECKBOX | WS_TABSTOP,7,85,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_QUA,222,83,38,12 END DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 107, 0, 267, 154 @@ -691,6 +662,40 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,218,205,44,10 END +DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 107, 0, 267, 154 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "ISA RTC:",IDT_1767,7,9,48,10 + COMBOBOX IDC_COMBO_ISARTC,64,7,155,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISARTC,222,7,38,12 + + GROUPBOX "ISA Memory Expansion",IDC_GROUP_ISAMEM,7,28,253,93 + LTEXT "Card 1:",IDT_1763,16,45,48,10 + COMBOBOX IDC_COMBO_ISAMEM_1,73,43,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_1,213,43,38,12 + LTEXT "Card 2:",IDT_1764,16,64,48,10 + COMBOBOX IDC_COMBO_ISAMEM_2,73,62,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_2,213,62,38,12 + LTEXT "Card 3:",IDT_1765,16,83,48,10 + COMBOBOX IDC_COMBO_ISAMEM_3,73,81,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_3,213,81,38,12 + LTEXT "Card 4:",IDT_1766,16,102,48,10 + COMBOBOX IDC_COMBO_ISAMEM_4,73,100,137,120, + CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_4,213,100,38,12 + + CONTROL "ISABugger device",IDC_CHECK_BUGGER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,128,94,10 + + CONTROL "POST card",IDC_CHECK_POSTCARD,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,128,94,10 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -753,6 +758,7 @@ END 249 ICON DISCARDABLE "win/icons/cdrom_disabled.ico" 250 ICON DISCARDABLE "win/icons/zip_disabled.ico" 251 ICON DISCARDABLE "win/icons/mo_disabled.ico" +252 ICON DISCARDABLE "win/icons/storage_controllers.ico" #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -938,11 +944,11 @@ BEGIN IDS_2068 "Sound" IDS_2069 "Network" IDS_2070 "Ports (COM & LPT)" - IDS_2071 "Other peripherals" + IDS_2071 "Storage controllers" IDS_2072 "Hard disks" IDS_2073 "Floppy & CD-ROM drives" IDS_2074 "Other removable devices" - IDS_2075 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + IDS_2075 "Other peripherals" IDS_2076 "Surface images (*.86F)\0*.86F\0" IDS_2077 "Click to capture mouse" IDS_2078 "Press F8+F12 to release mouse" @@ -1031,6 +1037,7 @@ BEGIN IDS_2137 "Reset" IDS_2138 "Don't reset" IDS_2139 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" + IDS_2140 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" END STRINGTABLE DISCARDABLE diff --git a/src/win/icons/storage_controllers.ico b/src/win/icons/storage_controllers.ico new file mode 100644 index 0000000000000000000000000000000000000000..8fd38558abc274876797b6df284d01f68bb5da73 GIT binary patch literal 1150 zcmZQzU}Ruq5D);-3Je)63=Con3=A3!3=9Gc3=9ek5OD?u1_lQf5Q&PllqBVJb=8~= z_0*G$3^c1u47B@9jP>T5nHa7#H#1xZ!XP$C3?v6q15yjp1JY}#ui4=0;&imEwB%WT zfB*M6bLRY8ym;~dB}EACvpc=7+KQ>Xs#-@pI=wr$(~uU)(L|I(#P|Ie8-=l|r%lmB;hb%FI)R8;&g zC@A=!m6i2BGc)tQzrWv|g$ozH0_i_-;snw9)6>)c$Hm3{kB*LhwP?|z7e|g9`9E*o zy#I6O&IP*}Wbd?T)BaDHG6ih^#EBFCPna;_e|LBH|LW@M|EZ~||6^lgLHb`zoH+4m zQ&ZFb`Sa)hU$}4~*v%mQAhSSzpEPOG|IW_N|8;eB|I5qE|5sI2{jaaD2eVUCQ=e2< zSD!v}=FI=or%w~@{+yf~u>XUDgHJ73u;2v+{(k||4+?uwe9fLc8|)8Iyn*~MYu2p) zGiJ>AKXvNV{~&*~x3`1h@PA553M~9yOrAXXd2@3!SPe)YNDoLoDEvTrdU|^Px3si? z{asmE3HEz!Z7taUDJdz>%FD}79zA;W|Jk!={~tJTfMEO=78d@`%gg%@io=kQkQ1Qz zqs0Fp{pZe|1E)EV+d=7I(V|8Fmn~cNfBEv|;B*WM3y@zx@tmKZkK+I7)2BZNh28Pv z$N%5CbLao<+qeJUym|BgwQJY@U%7JSKgez8&!7JfiepeXA3JvJ|K`n`|M&Iv{ZCF# zex8$)Q@Ul#md_x44<9}Rn}JI|D2;&3IC$_ND6M`@NJuCFvMB+J3T!;gF$*gdKno0|0fqW IF#i7!03l7Tt^fc4 literal 0 HcmV?d00001 diff --git a/src/win/win_media_menu.c b/src/win/win_media_menu.c index d7e6b6cba..e04329c93 100644 --- a/src/win/win_media_menu.c +++ b/src/win/win_media_menu.c @@ -450,7 +450,7 @@ media_menu_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_CDROM_IMAGE: - if (!file_dlg_w_st(hwnd, IDS_2075, cdrom[id].image_path, NULL, 0)) { + if (!file_dlg_w_st(hwnd, IDS_2140, cdrom[id].image_path, NULL, 0)) { cdrom_mount(id, wopenfilestring); } break; diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 183b9920f..f644b8a80 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -1531,14 +1531,14 @@ static LRESULT CALLBACK #else static BOOL CALLBACK #endif -win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +win_settings_storage_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { int c, d; - int e, is_at; + int is_at; LPTSTR lptsTemp; char *stransi; - const device_t *scsi_dev, *dev; - const device_t *fdc_dev, *hdc_dev; + const device_t *scsi_dev, *fdc_dev; + const device_t *hdc_dev; switch (message) { case WM_INITDIALOG: @@ -1643,48 +1643,6 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa settings_enable_window(hdlg, IDC_BUTTON_IDE_QUA, is_at && temp_ide_qua); settings_set_check(hdlg, IDC_CHECK_IDE_TER, temp_ide_ter); settings_set_check(hdlg, IDC_CHECK_IDE_QUA, temp_ide_qua); - settings_set_check(hdlg, IDC_CHECK_BUGGER, temp_bugger); - settings_set_check(hdlg, IDC_CHECK_POSTCARD, temp_postcard); - - /* Populate the ISA RTC card dropdown. */ - e = 0; - settings_reset_content(hdlg, IDC_COMBO_ISARTC); - for (d = 0; ; d++) { - generate_device_name(isartc_get_device(d), isartc_get_internal_name(d), 0); - - if (!device_name[0]) - break; - - if (d == 0) { - settings_add_string(hdlg, IDC_COMBO_ISARTC, win_get_string(IDS_2103)); - settings_set_cur_sel(hdlg, IDC_COMBO_ISARTC, 0); - } else - settings_add_string(hdlg, IDC_COMBO_ISARTC, (LPARAM) device_name); - settings_list_to_device[1][e] = d; - if (d == temp_isartc) - settings_set_cur_sel(hdlg, IDC_COMBO_ISARTC, e); - e++; - } - settings_enable_window(hdlg, IDC_CONFIGURE_ISARTC, temp_isartc != 0); - - /* Populate the ISA memory card dropdowns. */ - settings_reset_content(hdlg, IDC_COMBO_ISAMEM_1 + c); - for (c = 0; c < ISAMEM_MAX; c++) { - for (d = 0; ; d++) { - generate_device_name(isamem_get_device(d), (char *) isamem_get_internal_name(d), 0); - - if (!device_name[0]) - break; - - if (d == 0) { - settings_add_string(hdlg, IDC_COMBO_ISAMEM_1 + c, win_get_string(IDS_2103)); - settings_set_cur_sel(hdlg, IDC_COMBO_ISAMEM_1 + c, 0); - } else - settings_add_string(hdlg, IDC_COMBO_ISAMEM_1 + c, (LPARAM) device_name); - } - settings_set_cur_sel(hdlg, IDC_COMBO_ISAMEM_1 + c, temp_isamem[c]); - settings_enable_window(hdlg, IDC_CONFIGURE_ISAMEM_1 + c, temp_isamem[c] != 0); - } free(stransi); free(lptsTemp); @@ -1723,30 +1681,6 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa settings_enable_window(hdlg, IDC_CONFIGURE_SCSI, scsi_card_has_config(temp_scsi_card)); break; - case IDC_CONFIGURE_ISARTC: - temp_isartc = settings_list_to_device[1][settings_get_cur_sel(hdlg, IDC_COMBO_ISARTC)]; - temp_deviceconfig |= deviceconfig_open(hdlg, (void *)isartc_get_device(temp_isartc)); - break; - - case IDC_COMBO_ISARTC: - temp_isartc = settings_list_to_device[1][settings_get_cur_sel(hdlg, IDC_COMBO_ISARTC)]; - settings_enable_window(hdlg, IDC_CONFIGURE_ISARTC, temp_isartc != 0); - break; - - case IDC_COMBO_ISAMEM_1: case IDC_COMBO_ISAMEM_2: - case IDC_COMBO_ISAMEM_3: case IDC_COMBO_ISAMEM_4: - c = LOWORD(wParam) - IDC_COMBO_ISAMEM_1; - temp_isamem[c] = settings_get_cur_sel(hdlg, LOWORD(wParam)); - settings_enable_window(hdlg, IDC_CONFIGURE_ISAMEM_1 + c, temp_isamem[c] != 0); - break; - - case IDC_CONFIGURE_ISAMEM_1: case IDC_CONFIGURE_ISAMEM_2: - case IDC_CONFIGURE_ISAMEM_3: case IDC_CONFIGURE_ISAMEM_4: - c = LOWORD(wParam) - IDC_CONFIGURE_ISAMEM_1; - dev = isamem_get_device(temp_isamem[c]); - temp_deviceconfig |= deviceconfig_inst_open(hdlg, (void *)dev, c + 1); - break; - case IDC_CHECK_IDE_TER: temp_ide_ter = settings_get_check(hdlg, IDC_CHECK_IDE_TER); settings_enable_window(hdlg, IDC_BUTTON_IDE_TER, temp_ide_ter); @@ -1771,11 +1705,8 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa temp_hdc = settings_list_to_hdc[settings_get_cur_sel(hdlg, IDC_COMBO_HDC)]; temp_fdc_card = settings_list_to_fdc[settings_get_cur_sel(hdlg, IDC_COMBO_FDC)]; temp_scsi_card = settings_list_to_device[0][settings_get_cur_sel(hdlg, IDC_COMBO_SCSI)]; - temp_isartc = settings_list_to_device[1][settings_get_cur_sel(hdlg, IDC_COMBO_ISARTC)]; temp_ide_ter = settings_get_check(hdlg, IDC_CHECK_IDE_TER); temp_ide_qua = settings_get_check(hdlg, IDC_CHECK_IDE_QUA); - temp_bugger = settings_get_check(hdlg, IDC_CHECK_BUGGER); - temp_postcard = settings_get_check(hdlg, IDC_CHECK_POSTCARD); default: return FALSE; @@ -2187,9 +2118,11 @@ win_settings_hard_disks_update_item(HWND hdlg, int i, int column) wsprintf(szText, plat_get_string(IDS_4610), temp_hdd[i].esdi_channel >> 1, temp_hdd[i].esdi_channel & 1); break; case HDD_BUS_IDE: - case HDD_BUS_ATAPI: wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); break; + case HDD_BUS_ATAPI: + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); + break; case HDD_BUS_SCSI: wsprintf(szText, plat_get_string(IDS_4613), temp_hdd[i].scsi_id); break; @@ -2256,9 +2189,11 @@ win_settings_hard_disks_recalc_list(HWND hdlg) wsprintf(szText, plat_get_string(IDS_4610), temp_hdd[i].esdi_channel >> 1, temp_hdd[i].esdi_channel & 1); break; case HDD_BUS_IDE: - case HDD_BUS_ATAPI: wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); break; + case HDD_BUS_ATAPI: + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); + break; case HDD_BUS_SCSI: wsprintf(szText, plat_get_string(IDS_4613), temp_hdd[i].scsi_id); break; @@ -2322,7 +2257,7 @@ static void win_settings_hard_disks_resize_columns(HWND hdlg) { /* Bus, File, Cylinders, Heads, Sectors, Size */ - int iCol, width[C_COLUMNS_HARD_DISKS] = {130, 130, 41, 25, 25, 41}; + int iCol, width[C_COLUMNS_HARD_DISKS] = {104, 177, 50, 26, 32, 50}; HWND hwndList = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); for (iCol = 0; iCol < C_COLUMNS_HARD_DISKS; iCol++) @@ -2345,24 +2280,27 @@ win_settings_hard_disks_init_columns(HWND hdlg) switch(iCol) { case 0: /* Bus */ - lvc.cx = 130; + lvc.cx = 104; + lvc.fmt = LVCFMT_LEFT; + break; + case 1: /* File */ + lvc.cx = 177; lvc.fmt = LVCFMT_LEFT; break; case 2: /* Cylinders */ - lvc.cx = 41; + lvc.cx = 50; lvc.fmt = LVCFMT_RIGHT; break; case 3: /* Heads */ - case 4: /* Sectors */ - lvc.cx = 25; + lvc.cx = 26; lvc.fmt = LVCFMT_RIGHT; break; - case 1: /* File */ - lvc.cx = 130; - lvc.fmt = LVCFMT_LEFT; + case 4: /* Sectors */ + lvc.cx = 32; + lvc.fmt = LVCFMT_RIGHT; break; case 5: /* Size (MB) 8 */ - lvc.cx = 41; + lvc.cx = 50; lvc.fmt = LVCFMT_RIGHT; break; } @@ -3762,9 +3700,9 @@ win_settings_floppy_drives_resize_columns(HWND hdlg) { HWND hwndList = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); - ListView_SetColumnWidth(hwndList, 0, MulDiv(250, dpi, 96)); - ListView_SetColumnWidth(hwndList, 1, MulDiv(50, dpi, 96)); - ListView_SetColumnWidth(hwndList, 2, MulDiv(75, dpi, 96)); + ListView_SetColumnWidth(hwndList, 0, MulDiv(292, dpi, 96)); + ListView_SetColumnWidth(hwndList, 1, MulDiv(58, dpi, 96)); + ListView_SetColumnWidth(hwndList, 2, MulDiv(89, dpi, 96)); } @@ -3779,7 +3717,7 @@ win_settings_floppy_drives_init_columns(HWND hdlg) lvc.iSubItem = 0; lvc.pszText = plat_get_string(IDS_2092); - lvc.cx = 250; + lvc.cx = 292; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) @@ -3788,7 +3726,7 @@ win_settings_floppy_drives_init_columns(HWND hdlg) lvc.iSubItem = 1; lvc.pszText = plat_get_string(IDS_2059); - lvc.cx = 50; + lvc.cx = 58; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) @@ -3797,7 +3735,7 @@ win_settings_floppy_drives_init_columns(HWND hdlg) lvc.iSubItem = 2; lvc.pszText = plat_get_string(IDS_2087); - lvc.cx = 75; + lvc.cx = 89; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 2, &lvc) == -1) @@ -3813,8 +3751,8 @@ win_settings_cdrom_drives_resize_columns(HWND hdlg) { HWND hwndList = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); - ListView_SetColumnWidth(hwndList, 0, MulDiv(342, dpi, 96)); - ListView_SetColumnWidth(hwndList, 1, MulDiv(50, dpi, 96)); + ListView_SetColumnWidth(hwndList, 0, MulDiv(292, dpi, 96)); + ListView_SetColumnWidth(hwndList, 1, MulDiv(147, dpi, 96)); } @@ -3829,7 +3767,7 @@ win_settings_cdrom_drives_init_columns(HWND hdlg) lvc.iSubItem = 0; lvc.pszText = plat_get_string(IDS_2081); - lvc.cx = 342; + lvc.cx = 292; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) @@ -3838,7 +3776,7 @@ win_settings_cdrom_drives_init_columns(HWND hdlg) lvc.iSubItem = 1; lvc.pszText = plat_get_string(IDS_2053); - lvc.cx = 50; + lvc.cx = 147; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) @@ -3854,8 +3792,8 @@ win_settings_mo_drives_resize_columns(HWND hdlg) { HWND hwndList = GetDlgItem(hdlg, IDC_LIST_MO_DRIVES); - ListView_SetColumnWidth(hwndList, 0, MulDiv(120, dpi, 96)); - ListView_SetColumnWidth(hwndList, 1, MulDiv(260, dpi, 96)); + ListView_SetColumnWidth(hwndList, 0, MulDiv(292, dpi, 96)); + ListView_SetColumnWidth(hwndList, 1, MulDiv(147, dpi, 96)); } @@ -3870,7 +3808,7 @@ win_settings_mo_drives_init_columns(HWND hdlg) lvc.iSubItem = 0; lvc.pszText = plat_get_string(IDS_2081); - lvc.cx = 120; + lvc.cx = 292; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) @@ -3879,7 +3817,7 @@ win_settings_mo_drives_init_columns(HWND hdlg) lvc.iSubItem = 1; lvc.pszText = plat_get_string(IDS_2092); - lvc.cx = 260; + lvc.cx = 147; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) @@ -3895,8 +3833,8 @@ win_settings_zip_drives_resize_columns(HWND hdlg) { HWND hwndList = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); - ListView_SetColumnWidth(hwndList, 0, MulDiv(342, dpi, 96)); - ListView_SetColumnWidth(hwndList, 1, MulDiv(50, dpi, 96)); + ListView_SetColumnWidth(hwndList, 0, MulDiv(292, dpi, 96)); + ListView_SetColumnWidth(hwndList, 1, MulDiv(147, dpi, 96)); } @@ -3911,7 +3849,7 @@ win_settings_zip_drives_init_columns(HWND hdlg) lvc.iSubItem = 0; lvc.pszText = plat_get_string(IDS_2081); - lvc.cx = 342; + lvc.cx = 292; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) @@ -3920,7 +3858,7 @@ win_settings_zip_drives_init_columns(HWND hdlg) lvc.iSubItem = 1; lvc.pszText = plat_get_string(IDS_2092); - lvc.cx = 50; + lvc.cx = 147; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) @@ -4845,6 +4783,112 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam } +#if defined(__amd64__) || defined(__aarch64__) +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + int c, d; + int e; + LPTSTR lptsTemp; + char *stransi; + const device_t *dev; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); + stransi = (char *) malloc(512); + + /* Populate the ISA RTC card dropdown. */ + e = 0; + settings_reset_content(hdlg, IDC_COMBO_ISARTC); + for (d = 0; ; d++) { + generate_device_name(isartc_get_device(d), isartc_get_internal_name(d), 0); + + if (!device_name[0]) + break; + + if (d == 0) { + settings_add_string(hdlg, IDC_COMBO_ISARTC, win_get_string(IDS_2103)); + settings_set_cur_sel(hdlg, IDC_COMBO_ISARTC, 0); + } else + settings_add_string(hdlg, IDC_COMBO_ISARTC, (LPARAM) device_name); + settings_list_to_device[1][e] = d; + if (d == temp_isartc) + settings_set_cur_sel(hdlg, IDC_COMBO_ISARTC, e); + e++; + } + settings_enable_window(hdlg, IDC_CONFIGURE_ISARTC, temp_isartc != 0); + + /* Populate the ISA memory card dropdowns. */ + for (c = 0; c < ISAMEM_MAX; c++) { + settings_reset_content(hdlg, IDC_COMBO_ISAMEM_1 + c); + for (d = 0; ; d++) { + generate_device_name(isamem_get_device(d), (char *) isamem_get_internal_name(d), 0); + + if (!device_name[0]) + break; + + if (d == 0) { + settings_add_string(hdlg, IDC_COMBO_ISAMEM_1 + c, win_get_string(IDS_2103)); + settings_set_cur_sel(hdlg, IDC_COMBO_ISAMEM_1 + c, 0); + } else + settings_add_string(hdlg, IDC_COMBO_ISAMEM_1 + c, (LPARAM) device_name); + } + settings_set_cur_sel(hdlg, IDC_COMBO_ISAMEM_1 + c, temp_isamem[c]); + settings_enable_window(hdlg, IDC_CONFIGURE_ISAMEM_1 + c, temp_isamem[c] != 0); + } + + settings_set_check(hdlg, IDC_CHECK_BUGGER, temp_bugger); + settings_set_check(hdlg, IDC_CHECK_POSTCARD, temp_postcard); + + free(stransi); + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_CONFIGURE_ISARTC: + temp_isartc = settings_list_to_device[1][settings_get_cur_sel(hdlg, IDC_COMBO_ISARTC)]; + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)isartc_get_device(temp_isartc)); + break; + + case IDC_COMBO_ISARTC: + temp_isartc = settings_list_to_device[1][settings_get_cur_sel(hdlg, IDC_COMBO_ISARTC)]; + settings_enable_window(hdlg, IDC_CONFIGURE_ISARTC, temp_isartc != 0); + break; + + case IDC_COMBO_ISAMEM_1: case IDC_COMBO_ISAMEM_2: + case IDC_COMBO_ISAMEM_3: case IDC_COMBO_ISAMEM_4: + c = LOWORD(wParam) - IDC_COMBO_ISAMEM_1; + temp_isamem[c] = settings_get_cur_sel(hdlg, LOWORD(wParam)); + settings_enable_window(hdlg, IDC_CONFIGURE_ISAMEM_1 + c, temp_isamem[c] != 0); + break; + + case IDC_CONFIGURE_ISAMEM_1: case IDC_CONFIGURE_ISAMEM_2: + case IDC_CONFIGURE_ISAMEM_3: case IDC_CONFIGURE_ISAMEM_4: + c = LOWORD(wParam) - IDC_CONFIGURE_ISAMEM_1; + dev = isamem_get_device(temp_isamem[c]); + temp_deviceconfig |= deviceconfig_inst_open(hdlg, (void *)dev, c + 1); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + temp_isartc = settings_list_to_device[1][settings_get_cur_sel(hdlg, IDC_COMBO_ISARTC)]; + temp_bugger = settings_get_check(hdlg, IDC_CHECK_BUGGER); + temp_postcard = settings_get_check(hdlg, IDC_CHECK_POSTCARD); + + default: + return FALSE; + } + return FALSE; +} + + void win_settings_show_child(HWND hwndParent, DWORD child_id) { if (child_id == displayed_category) @@ -4875,8 +4919,8 @@ void win_settings_show_child(HWND hwndParent, DWORD child_id) case SETTINGS_PAGE_PORTS: hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PORTS, hwndParent, win_settings_ports_proc); break; - case SETTINGS_PAGE_PERIPHERALS: - hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PERIPHERALS, hwndParent, win_settings_peripherals_proc); + case SETTINGS_PAGE_STORAGE: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_STORAGE, hwndParent, win_settings_storage_proc); break; case SETTINGS_PAGE_HARD_DISKS: hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_HARD_DISKS, hwndParent, win_settings_hard_disks_proc); @@ -4887,6 +4931,9 @@ void win_settings_show_child(HWND hwndParent, DWORD child_id) case SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES: hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_OTHER_REMOVABLE_DEVICES, hwndParent, win_settings_other_removable_devices_proc); break; + case SETTINGS_PAGE_PERIPHERALS: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PERIPHERALS, hwndParent, win_settings_peripherals_proc); + break; default: fatal("Invalid child dialog ID\n"); return; @@ -4905,7 +4952,7 @@ win_settings_main_insert_categories(HWND hwndList) lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; lvI.stateMask = lvI.iSubItem = lvI.state = 0; - for (i = 0; i < 10; i++) { + for (i = 0; i < 11; i++) { lvI.pszText = plat_get_string(IDS_2065+i); lvI.iItem = i; lvI.iImage = i; @@ -4944,6 +4991,38 @@ win_settings_confirm(HWND hdlg, int button) } +static BOOL +win_settings_categories_init_columns(HWND hdlg) +{ + LVCOLUMN lvc; + int iCol; + HWND hwndList = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = plat_get_string(2048); + + lvc.cx = 171; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, iCol, &lvc) == -1) + return FALSE; + + win_settings_hard_disks_resize_columns(hdlg); + return TRUE; +} + + +static void +win_settings_categories_resize_columns(HWND hdlg) +{ + HWND hwndList = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + + ListView_SetColumnWidth(hwndList, 0, MulDiv(171, dpi, 96)); +} + + #if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else @@ -4953,7 +5032,7 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h = NULL; int category, i = 0, j = 0; - const uint8_t cat_icons[12] = { 240, 241, 242, 243, 96, 244, 245, 80, 246, 247, 0 }; + const uint8_t cat_icons[12] = { 240, 241, 242, 243, 96, 244, 252, 80, 246, 247, 245, 0 }; hwndParentDialog = hdlg; @@ -4963,6 +5042,7 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) win_settings_init(); displayed_category = -1; h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + win_settings_categories_init_columns(hdlg); image_list_init(hdlg, IDC_SETTINGSCATLIST, (const uint8_t *) cat_icons); win_settings_main_insert_categories(h); settings_listview_select(hdlg, IDC_SETTINGSCATLIST, first_cat); @@ -4994,8 +5074,10 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return TRUE; } break; + case WM_DPICHANGED: dpi = HIWORD(wParam); + win_settings_categories_resize_columns(hdlg); image_list_init(hdlg, IDC_SETTINGSCATLIST, (const uint8_t *) cat_icons); break; default: From c11f91f2943fa50403913e3b9556fb471abd5494 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Nov 2020 05:44:04 +0100 Subject: [PATCH 20/67] Fixed an ATi Mach64 warning. --- src/video/vid_ati_mach64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index d7d9f1e90..64a36583a 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -1740,7 +1740,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) mach64_t *mach64 = (mach64_t *)p; uint8_t gpio_state; - uint8_t ret; + uint8_t ret = 0xff; if (!(addr & 0x400)) { mach64_log("nmach64_ext_readb: addr=%04x\n", addr); From 97676a7e866a4fe30a23ece6aecfc9ca33579944 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Nov 2020 06:43:20 +0100 Subject: [PATCH 21/67] Increased the device arrays in the Settings dialog to 256 devices. --- src/win/win_settings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index f644b8a80..a200adfa0 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -131,7 +131,7 @@ static uint32_t displayed_category = 0; extern int is486; static int listtomachinetype[256], listtomachine[256]; static int listtocpufamily[256], listtocpu[256]; -static int settings_list_to_device[2][20], settings_list_to_fdc[20]; +static int settings_list_to_device[2][256], settings_list_to_fdc[20]; static int settings_list_to_midi[20], settings_list_to_midi_in[20]; static int settings_list_to_hdc[20]; From ca11d7b776e295e4d22469817ff5b76c14935cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Fri, 20 Nov 2020 15:39:33 +0100 Subject: [PATCH 22/67] Update the Settings save confirmation dialog --- src/include/86box/language.h | 5 ++++- src/include/86box/ui.h | 1 + src/win/86Box.rc | 3 +++ src/win/win_dialog.c | 5 +++-- src/win/win_settings.c | 5 ++++- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/include/86box/language.h b/src/include/86box/language.h index 451811964..180b39b37 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -114,6 +114,9 @@ #define IDS_2138 2138 // "Don't Reset" #define IDS_2139 2139 // "MO images (*.IM?)\0*.IM?..." #define IDS_2140 2140 // "CD-ROM images (*.ISO;*.CU.." +#define IDS_2141 2141 // "Save" +#define IDS_2142 2142 // "Don't save" +#define IDS_2143 2143 // "This will hard reset the virtual..." #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -221,7 +224,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 93 +#define STR_NUM_2048 96 #define STR_NUM_3072 11 #define STR_NUM_4096 39 #define STR_NUM_4352 6 diff --git a/src/include/86box/ui.h b/src/include/86box/ui.h index 1c4c5aee1..15950c6e6 100644 --- a/src/include/86box/ui.h +++ b/src/include/86box/ui.h @@ -34,6 +34,7 @@ extern "C" { #define MBX_ERROR 2 #define MBX_QUESTION 3 #define MBX_QUESTION_YN 4 +#define MBX_QUESTION_OK 8 #define MBX_QMARK 0x10 #define MBX_WARNING 0x20 #define MBX_FATAL 0x40 diff --git a/src/win/86Box.rc b/src/win/86Box.rc index c0bb24bc8..007d12b07 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -1038,6 +1038,9 @@ BEGIN IDS_2138 "Don't reset" IDS_2139 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" IDS_2140 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + IDS_2141 "Save" + IDS_2142 "Don't save" + IDS_2143 "This will hard reset the virtual machine." END STRINGTABLE DISCARDABLE diff --git a/src/win/win_dialog.c b/src/win/win_dialog.c index 1e48b7d40..83f19b4f1 100644 --- a/src/win/win_dialog.c +++ b/src/win/win_dialog.c @@ -100,13 +100,14 @@ ui_msgbox_ex(int flags, void *header, void *message, void *btn1, void *btn2, voi case MBX_QUESTION: /* question */ case MBX_QUESTION_YN: + case MBX_QUESTION_OK: if (!btn1) /* replace default "OK" button with "Yes" button */ - tdconfig.dwCommonButtons = TDCBF_YES_BUTTON; + tdconfig.dwCommonButtons = (flags & MBX_QUESTION_OK) ? TDCBF_OK_BUTTON : TDCBF_YES_BUTTON; if (btn2) /* "No" button */ tdbuttons[tdconfig.cButtons++] = tdb_no; else - tdconfig.dwCommonButtons |= TDCBF_NO_BUTTON; + tdconfig.dwCommonButtons |= (flags & MBX_QUESTION_OK) ? TDCBF_CANCEL_BUTTON : TDCBF_NO_BUTTON; if (flags & MBX_QUESTION) { if (btn3) /* "Cancel" button */ diff --git a/src/win/win_settings.c b/src/win/win_settings.c index a200adfa0..f6e0f0c8c 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -531,7 +531,10 @@ settings_msgbox_reset(int button) h = hwndMain; hwndMain = hwndParentDialog; - i = ui_msgbox_ex(MBX_QUESTION | MBX_LINKS, (wchar_t *) (button ? IDS_2051 : IDS_2123), NULL, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, NULL); + if (button) + i = ui_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING, (wchar_t *) IDS_2051, (wchar_t *) IDS_2142, (wchar_t *) IDS_2140, NULL, NULL); + else + i = ui_msgbox_ex(MBX_QUESTION | MBX_LINKS, (wchar_t *) IDS_2123, NULL, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, NULL); hwndMain = h; From 3c679960e1a043d557e121846ac53573a04693cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Fri, 20 Nov 2020 17:10:50 +0100 Subject: [PATCH 23/67] Update the device configuration dialog --- src/include/86box/language.h | 3 ++- src/win/86Box.rc | 1 + src/win/win_devconf.c | 21 +++++++++++---------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/include/86box/language.h b/src/include/86box/language.h index 180b39b37..9d8634bb4 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -117,6 +117,7 @@ #define IDS_2141 2141 // "Save" #define IDS_2142 2142 // "Don't save" #define IDS_2143 2143 // "This will hard reset the virtual..." +#define IDS_2144 2144 // "%hs Device Configuration" #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -224,7 +225,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 96 +#define STR_NUM_2048 97 #define STR_NUM_3072 11 #define STR_NUM_4096 39 #define STR_NUM_4352 6 diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 007d12b07..9e5982464 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -1041,6 +1041,7 @@ BEGIN IDS_2141 "Save" IDS_2142 "Don't save" IDS_2143 "This will hard reset the virtual machine." + IDS_2144 "%hs Device Configuration" END STRINGTABLE DISCARDABLE diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index 18b567d79..1ae0eddc2 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -454,7 +454,8 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) *data++ = 0; /*no menu*/ *data++ = 0; /*predefined dialog box class*/ - data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 120); + + data += wsprintf(data, plat_get_string(IDS_2144), device->name) + 1; *data++ = 9; /*Point*/ data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 120); @@ -499,7 +500,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) item->cx = 140; item->cy = 150; - item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; @@ -514,7 +515,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; item->cx = 60; @@ -561,7 +562,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; item->cx = 60; @@ -628,7 +629,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) /*Static text*/ item = (DLGITEMTEMPLATE *)data; item->x = 10; - item->y = y; + item->y = y + 2; item->id = id++; item->cx = 60; @@ -659,8 +660,8 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) dlg->cdit = (id - IDC_CONFIG_BASE) + 2; item = (DLGITEMTEMPLATE *)data; - item->x = 20; - item->y = y; + item->x = 100; + item->y = y + 5; item->cx = 50; item->cy = 14; item->id = IDOK; /* OK button identifier */ @@ -677,8 +678,8 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) data++; item = (DLGITEMTEMPLATE *)data; - item->x = 80; - item->y = y; + item->x = 160; + item->y = y + 5; item->cx = 50; item->cy = 14; item->id = IDCANCEL; /* OK button identifier */ @@ -691,7 +692,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); *data++ = 0; /* no creation data */ - dlg->cy = y + 20; + dlg->cy = y + 25; device_set_context(&config_device, device, inst); From 3506ad90e00a0b5168e0297b13ee6a25565da373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Fri, 20 Nov 2020 18:27:25 +0100 Subject: [PATCH 24/67] Closing Settings now equals to clicking Cancel --- src/win/win_settings.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index f6e0f0c8c..05ee5cec5 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -520,7 +520,7 @@ win_settings_changed(void) static int -settings_msgbox_reset(int button) +settings_msgbox_reset() { int changed, i = 0; HWND h; @@ -531,10 +531,7 @@ settings_msgbox_reset(int button) h = hwndMain; hwndMain = hwndParentDialog; - if (button) - i = ui_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING, (wchar_t *) IDS_2051, (wchar_t *) IDS_2142, (wchar_t *) IDS_2140, NULL, NULL); - else - i = ui_msgbox_ex(MBX_QUESTION | MBX_LINKS, (wchar_t *) IDS_2123, NULL, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, NULL); + i = ui_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING, (wchar_t *) IDS_2051, (wchar_t *) IDS_2143, (wchar_t *) IDS_2141, NULL, NULL); hwndMain = h; @@ -4974,12 +4971,12 @@ static LRESULT CALLBACK #else static BOOL CALLBACK #endif -win_settings_confirm(HWND hdlg, int button) +win_settings_confirm(HWND hdlg) { int i; SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); - i = settings_msgbox_reset(button); + i = settings_msgbox_reset(); if (i > 0) { if (i == 2) win_settings_save(); @@ -4988,9 +4985,9 @@ win_settings_confirm(HWND hdlg, int button) EndDialog(hdlg, 0); win_notify_dlg_closed(); - return button ? TRUE : FALSE; + return TRUE; } else - return button ? FALSE : TRUE; + return FALSE; } @@ -5065,11 +5062,14 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) } break; case WM_CLOSE: - return win_settings_confirm(hdlg, 0); + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + win_notify_dlg_closed(); + return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: - return win_settings_confirm(hdlg, 1); + return win_settings_confirm(hdlg); case IDCANCEL: DestroyWindow(hwndChildDialog); EndDialog(hdlg, 0); From 8aab3da7693814dca8a5625f2e754fa2ae7f7e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Fri, 20 Nov 2020 18:42:22 +0100 Subject: [PATCH 25/67] Clean up resource IDs --- src/include/86box/language.h | 27 ++++++++++++--------------- src/win/86Box.rc | 13 +++++-------- src/win/win_devconf.c | 2 +- src/win/win_settings.c | 2 +- 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/include/86box/language.h b/src/include/86box/language.h index 9d8634bb4..5ae5bb169 100644 --- a/src/include/86box/language.h +++ b/src/include/86box/language.h @@ -24,7 +24,7 @@ #define IDS_STRINGS 2048 // "86Box" #define IDS_2049 2049 // "Error" #define IDS_2050 2050 // "Fatal error" -#define IDS_2051 2051 // "Are you sure you want to save..." +#define IDS_2051 2051 // "" #define IDS_2052 2052 // "Press CTRL+ALT+PAGE DOWN..." #define IDS_2053 2053 // "Speed" #define IDS_2054 2054 // "ZIP %i (%03i): %ls" @@ -94,9 +94,9 @@ #define IDS_2118 2118 // "Internal controller" #define IDS_2119 2119 // "Exit" #define IDS_2120 2120 // "No ROMs found" -#define IDS_2121 2121 // "Save changes\nThis will hard..." -#define IDS_2122 2122 // "Discard changes\nAll changes..." -#define IDS_2123 2123 // "Do you want to save the settings?" +#define IDS_2121 2121 // "Do you want to save the settings?" +#define IDS_2122 2122 // "This will hard reset the virtual..." +#define IDS_2123 2123 // "Save" #define IDS_2124 2124 // "About 86Box" #define IDS_2125 2125 // "86Box v" EMU_VERSION #define IDS_2126 2126 // "An emulator of old computers..." @@ -109,15 +109,12 @@ #define IDS_2133 2133 // LIB_NAME_FLUIDSYNTH " is required..." #define IDS_2134 2134 // "Entering fullscreen mode" #define IDS_2135 2135 // "Don't show this message again" -#define IDS_2136 2136 // "Don't Exit" +#define IDS_2136 2136 // "Don't exit" #define IDS_2137 2137 // "Reset" -#define IDS_2138 2138 // "Don't Reset" +#define IDS_2138 2138 // "Don't reset" #define IDS_2139 2139 // "MO images (*.IM?)\0*.IM?..." #define IDS_2140 2140 // "CD-ROM images (*.ISO;*.CU.." -#define IDS_2141 2141 // "Save" -#define IDS_2142 2142 // "Don't save" -#define IDS_2143 2143 // "This will hard reset the virtual..." -#define IDS_2144 2144 // "%hs Device Configuration" +#define IDS_2141 2141 // "%hs Device Configuration" #define IDS_4096 4096 // "Hard disk (%s)" #define IDS_4097 4097 // "%01i:%01i" @@ -144,7 +141,7 @@ #define IDS_4118 4118 // "The selected file will be..." #define IDS_4119 4119 // "Unsupported disk image" #define IDS_4120 4120 // "Overwrite" -#define IDS_4121 4121 // "Don't Overwrite" +#define IDS_4121 4121 // "Don't overwrite" #define IDS_4122 4122 // "Raw image (.img)" #define IDS_4123 4123 // "HDI image (.hdi)" #define IDS_4124 4124 // "HDX image (.hdx)" @@ -153,10 +150,10 @@ #define IDS_4127 4127 // "Differencing VHD (.vhd)" #define IDS_4128 4128 // "Large blocks (2 MB)" #define IDS_4129 4129 // "Small blocks (512 KB)" -#define IDS_4130 4130 // "VHD files (*.VHD)\0*.VHD\0All files (*.*)\0*.*\0" +#define IDS_4130 4130 // "VHD files (*.VHD)\0*.VHD\0All..." #define IDS_4131 4131 // "Select the parent VHD" -#define IDS_4132 4132 // "WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH..." -#define IDS_4133 4133 // "VHD Timestamp Mismatch" +#define IDS_4132 4132 // "This could mean that the parent..." +#define IDS_4133 4133 // "Parent and child disk timestamps..." #define IDS_4134 4134 // "Could not fix VHD timestamp." #define IDS_4352 4352 // "MFM/RLL" @@ -225,7 +222,7 @@ #define IDS_LANG_ENUS IDS_7168 -#define STR_NUM_2048 97 +#define STR_NUM_2048 94 #define STR_NUM_3072 11 #define STR_NUM_4096 39 #define STR_NUM_4352 6 diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 9e5982464..237e7f783 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -920,7 +920,7 @@ BEGIN 2048 "86Box" IDS_2049 "Error" IDS_2050 "Fatal error" - IDS_2051 "Are you sure you want to save the settings?" + IDS_2051 "" IDS_2052 "Press CTRL+ALT+PAGE DOWN to return to windowed mode." IDS_2053 "Speed" IDS_2054 "ZIP %03i %i (%s): %ls" @@ -998,9 +998,9 @@ BEGIN IDS_2118 "Internal controller" IDS_2119 "Exit" IDS_2120 "No ROMs found" - IDS_2121 "Save changes\nThis will hard reset the emulated machine." - IDS_2122 "Discard changes\nAll changes made to the settings will be lost." - IDS_2123 "Do you want to save the settings?" + IDS_2121 "Do you want to save the settings?" + IDS_2122 "This will hard reset the virtual machine." + IDS_2123 "Save" IDS_2124 "About 86Box" IDS_2125 "86Box v" EMU_VERSION IDS_2126 "An emulator of old computers\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information." @@ -1038,10 +1038,7 @@ BEGIN IDS_2138 "Don't reset" IDS_2139 "MO images (*.IM?;*.MDI)\0*.IM?;*.MDI\0All files (*.*)\0*.*\0" IDS_2140 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" - IDS_2141 "Save" - IDS_2142 "Don't save" - IDS_2143 "This will hard reset the virtual machine." - IDS_2144 "%hs Device Configuration" + IDS_2141 "%hs Device Configuration" END STRINGTABLE DISCARDABLE diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index 1ae0eddc2..d0469660c 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -455,7 +455,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) *data++ = 0; /*no menu*/ *data++ = 0; /*predefined dialog box class*/ - data += wsprintf(data, plat_get_string(IDS_2144), device->name) + 1; + data += wsprintf(data, plat_get_string(IDS_2141), device->name) + 1; *data++ = 9; /*Point*/ data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 120); diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 05ee5cec5..bd06279ae 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -531,7 +531,7 @@ settings_msgbox_reset() h = hwndMain; hwndMain = hwndParentDialog; - i = ui_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING, (wchar_t *) IDS_2051, (wchar_t *) IDS_2143, (wchar_t *) IDS_2141, NULL, NULL); + i = ui_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, (wchar_t *) IDS_2123, NULL, NULL); hwndMain = h; From 908258302be2d1fe83ea4c495ba9c9bf6fa73d3b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 20 Nov 2020 22:24:46 +0100 Subject: [PATCH 26/67] Ported the latest Voodoo 1/2 patches from PCem. --- src/video/vid_voodoo.c | 2 +- src/video/vid_voodoo_setup.c | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index d9929324a..e8d2ad7d3 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -390,7 +390,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) break; default: - fatal("voodoo_readl : bad addr %08X\n", addr); + voodoo_log("voodoo_readl : bad addr %08X\n", addr); temp = 0xffffffff; } diff --git a/src/video/vid_voodoo_setup.c b/src/video/vid_voodoo_setup.c index 283208960..74f312fd4 100644 --- a/src/video/vid_voodoo_setup.c +++ b/src/video/vid_voodoo_setup.c @@ -36,6 +36,24 @@ #include <86box/vid_voodoo_render.h> #include <86box/vid_voodoo_setup.h> +#ifdef ENABLE_VOODOO_SETUP_LOG +int voodoo_setup_do_log = ENABLE_VOODOO_SETUP_LOG; + +static void +voodoo_setup_log(const char *fmt, ...) +{ + va_list ap; + + if (voodoo_setup_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define voodoo_setup_log(fmt, ...) +#endif + void voodoo_triangle_setup(voodoo_t *voodoo) { @@ -152,8 +170,10 @@ void voodoo_triangle_setup(voodoo_t *voodoo) voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(verts[vc].sVx * 16.0f) & 0xffff); voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(verts[vc].sVy * 16.0f) & 0xffff); - if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) - fatal("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy); + if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) { + voodoo_setup_log("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy); + return; + } if (voodoo->sSetupMode & SETUPMODE_RGB) { From 77d7c0fb819a79ae2250fdebfea169623b15fe4d Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 20 Nov 2020 23:59:04 +0100 Subject: [PATCH 27/67] VHD fixes. --- src/disk/hdd_image.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index d506734d5..485f224fc 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -270,6 +270,8 @@ hdd_image_load(int id) int is_hdx[2] = { 0, 0 }; int is_vhd[2] = { 0, 0 }; int vhd_error = 0; + MVHDMeta *vhdm; + MVHDGeom geom; memset(empty_sector, 0, sizeof(empty_sector)); @@ -358,6 +360,7 @@ hdd_image_load(int id) full_size = ((uint64_t) hdd[id].spt) * ((uint64_t) hdd[id].hpc) * ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].last_sector = (full_size >> 9LL) - 1; wcstombs(fn_multibyte_buf, fn, sizeof fn_multibyte_buf); hdd_images[id].vhd = mvhd_create_fixed(fn_multibyte_buf, geometry, &vhd_error, NULL); @@ -460,10 +463,13 @@ hdd_image_load(int id) fatal("hdd_image_load(): VHD: Parent/child timestamp mismatch for VHD file '%s'\n", fn_multibyte_buf); } - full_size = hdd_images[id].vhd->footer.curr_sz; - hdd[id].tracks = hdd_images[id].vhd->footer.geom.cyl; - hdd[id].hpc = hdd_images[id].vhd->footer.geom.heads; - hdd[id].spt = hdd_images[id].vhd->footer.geom.spt; + mvhd_get_geometry(hdd_images[id].vhd); + hdd[id].spt = geom.spt; + hdd[id].hpc = geom.heads; + hdd[id].tracks = geom.cyl; + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; hdd_images[id].type = HDD_IMAGE_VHD; /* If we're here, this means there is a valid VHD footer in the image, which means that by definition, all valid sectors @@ -533,15 +539,17 @@ hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) } +uint32_t +hdd_image_get_last_sector(uint8_t id) +{ + return hdd_images[id].last_sector; +} + + uint32_t hdd_sectors(uint8_t id) { - if (hdd_images[id].type == HDD_IMAGE_VHD) { - return (uint32_t) (hdd_images[id].vhd->footer.curr_sz >> 9); - } else { - fseeko64(hdd_images[id].file, 0, SEEK_END); - return (uint32_t)((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9); - } + return hdd_image_get_last_sector(id) - 1; } @@ -648,13 +656,6 @@ hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) } -uint32_t -hdd_image_get_last_sector(uint8_t id) -{ - return hdd_images[id].last_sector; -} - - uint32_t hdd_image_get_pos(uint8_t id) { From ba35c158dbc96497e8fd5b8663679ddece4091f0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 21 Nov 2020 03:10:22 +0100 Subject: [PATCH 28/67] Fixed the PCI slots of the Soyo 4SA2. --- src/machine/m_at_386dx_486.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 2f4a11871..0a14926bf 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -730,8 +730,8 @@ machine_at_4sa2_init(const machine_t *model) device_add(&sis_85c496_device); pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); device_add(&pc87332_device); device_add(&keyboard_ps2_pci_device); From b83a32ccf8e55f6dd070a85b31ae8c1850b850c9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 21 Nov 2020 04:02:58 +0100 Subject: [PATCH 29/67] Improved STI fix. --- src/cpu/386.c | 5 +++-- src/cpu/386_dynarec.c | 30 +++++++++++++++--------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/cpu/386.c b/src/cpu/386.c index 940e01a76..3a3e36d58 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -257,6 +257,9 @@ exec386(int cycs) if (!use32) cpu_state.pc &= 0xffff; #endif + if (cpu_end_block_after_ins) + cpu_end_block_after_ins--; + if (cpu_state.abrt) { flags_rebuild(); tempi = cpu_state.abrt & ABRT_MASK; @@ -329,8 +332,6 @@ exec386(int cycs) } } - cpu_end_block_after_ins = 0; - ins_cycles -= cycles; tsc += ins_cycles; diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 552669434..4a8b3637e 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -349,6 +349,12 @@ exec386_dynarec_int(void) if (((cs + cpu_state.pc) >> 12) != pccache) CPU_BLOCK_END(); + if (cpu_end_block_after_ins) { + cpu_end_block_after_ins--; + if (!cpu_end_block_after_ins) + CPU_BLOCK_END(); + } + if (cpu_state.abrt) CPU_BLOCK_END(); if (smi_line) @@ -357,14 +363,8 @@ exec386_dynarec_int(void) CPU_BLOCK_END(); else if (nmi && nmi_enable && nmi_mask) CPU_BLOCK_END(); - else if ((cpu_state.flags & I_FLAG) && pic.int_pending) + else if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins) CPU_BLOCK_END(); - - if (cpu_end_block_after_ins) { - cpu_end_block_after_ins--; - if (!cpu_end_block_after_ins) - CPU_BLOCK_END(); - } } if (trap) { @@ -585,21 +585,21 @@ exec386_dynarec_dyn(void) #endif CPU_BLOCK_END(); + if (cpu_end_block_after_ins) { + cpu_end_block_after_ins--; + if (!cpu_end_block_after_ins) + CPU_BLOCK_END(); + } + if (smi_line) CPU_BLOCK_END(); else if (cpu_state.flags & T_FLAG) CPU_BLOCK_END(); else if (nmi && nmi_enable && nmi_mask) CPU_BLOCK_END(); - else if ((cpu_state.flags & I_FLAG) && pic.int_pending) + else if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins) CPU_BLOCK_END(); - if (cpu_end_block_after_ins) { - cpu_end_block_after_ins--; - if (!cpu_end_block_after_ins) - CPU_BLOCK_END(); - } - if (cpu_state.abrt) { if (!(cpu_state.abrt & ABRT_EXPECTED)) codegen_block_remove(); @@ -683,7 +683,7 @@ exec386_dynarec_dyn(void) CPU_BLOCK_END(); else if (nmi && nmi_enable && nmi_mask) CPU_BLOCK_END(); - else if ((cpu_state.flags & I_FLAG) && pic.int_pending) + else if ((cpu_state.flags & I_FLAG) && pic.int_pending && !cpu_end_block_after_ins) CPU_BLOCK_END(); if (cpu_end_block_after_ins) { From 68000092e24cdae098230955cc6a23a3b0214c83 Mon Sep 17 00:00:00 2001 From: sards3 Date: Sat, 21 Nov 2020 03:48:40 -0600 Subject: [PATCH 30/67] VHD: fix bug in multi-sector writes --- src/disk/minivhd/minivhd_io.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/disk/minivhd/minivhd_io.c b/src/disk/minivhd/minivhd_io.c index ddd17177e..4169d66f1 100644 --- a/src/disk/minivhd/minivhd_io.c +++ b/src/disk/minivhd/minivhd_io.c @@ -245,6 +245,10 @@ int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, voi for (s = offset; s < ls; s++) { blk = s / vhdm->sect_per_block; sib = s % vhdm->sect_per_block; + if (vhdm->bitmap.curr_block != blk && prev_blk >= 0) { + /* Write the sector bitmap for the previous block, before we replace it. */ + mvhd_write_curr_sect_bitmap(vhdm); + } if (vhdm->block_offset[blk] == MVHD_SPARSE_BLK) { /* "read" the sector bitmap first, before creating a new block, as the bitmap will be zero either way */ @@ -252,11 +256,7 @@ int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, voi mvhd_create_block(vhdm, blk); } if (blk != prev_blk) { - if (vhdm->bitmap.curr_block != blk) { - if (prev_blk >= 0) { - /* Write the sector bitmap for the previous block, before we replace it. */ - mvhd_write_curr_sect_bitmap(vhdm); - } + if (vhdm->bitmap.curr_block != blk) { mvhd_read_sect_bitmap(vhdm, blk); mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR); } else { @@ -276,4 +276,4 @@ int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, voi int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { return 0; -} \ No newline at end of file +} From f86ab08395d22bce6006a49c4821d92abd21ad30 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 21 Nov 2020 16:19:08 +0100 Subject: [PATCH 31/67] The geometry is now obtained normally. --- src/disk/hdd_image.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index 485f224fc..88e182d41 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -270,8 +270,6 @@ hdd_image_load(int id) int is_hdx[2] = { 0, 0 }; int is_vhd[2] = { 0, 0 }; int vhd_error = 0; - MVHDMeta *vhdm; - MVHDGeom geom; memset(empty_sector, 0, sizeof(empty_sector)); @@ -463,10 +461,9 @@ hdd_image_load(int id) fatal("hdd_image_load(): VHD: Parent/child timestamp mismatch for VHD file '%s'\n", fn_multibyte_buf); } - mvhd_get_geometry(hdd_images[id].vhd); - hdd[id].spt = geom.spt; - hdd[id].hpc = geom.heads; - hdd[id].tracks = geom.cyl; + hdd[id].tracks = hdd_images[id].vhd->footer.geom.cyl; + hdd[id].hpc = hdd_images[id].vhd->footer.geom.heads; + hdd[id].spt = hdd_images[id].vhd->footer.geom.spt; full_size = ((uint64_t) hdd[id].spt) * ((uint64_t) hdd[id].hpc) * ((uint64_t) hdd[id].tracks) << 9LL; From b45ba90b5936a1a32219c14fbb6a12a0527b96ea Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 21 Nov 2020 16:25:54 +0100 Subject: [PATCH 32/67] Latest PCem voodoo fifo changes are here. --- src/include/86box/vid_voodoo_common.h | 3 ++- src/video/vid_voodoo_banshee.c | 2 ++ src/video/vid_voodoo_fifo.c | 31 ++++++++++++++++++++------- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/include/86box/vid_voodoo_common.h b/src/include/86box/vid_voodoo_common.h index 073d2ca3d..fe2f0b32c 100644 --- a/src/include/86box/vid_voodoo_common.h +++ b/src/include/86box/vid_voodoo_common.h @@ -314,7 +314,8 @@ typedef struct voodoo_t volatile int params_read_idx[4], params_write_idx; uint32_t cmdfifo_base, cmdfifo_end, cmdfifo_size; - int cmdfifo_rp; + int cmdfifo_rp, cmdfifo_ret_addr; + int cmdfifo_in_sub; volatile int cmdfifo_depth_rd, cmdfifo_depth_wr; volatile int cmdfifo_enabled; uint32_t cmdfifo_amin, cmdfifo_amax; diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 7a46dc860..d7f78bd05 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -1203,6 +1203,8 @@ static void banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val) voodoo->cmdfifo_size = val; voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12); voodoo->cmdfifo_enabled = val & 0x100; + if (!voodoo->cmdfifo_enabled) + voodoo->cmdfifo_in_sub = 0; /*Not sure exactly when this should be reset*/ // banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); break; diff --git a/src/video/vid_voodoo_fifo.c b/src/video/vid_voodoo_fifo.c index 597c45051..9e1f9c61f 100644 --- a/src/video/vid_voodoo_fifo.c +++ b/src/video/vid_voodoo_fifo.c @@ -155,16 +155,19 @@ void voodoo_wait_for_swap_complete(voodoo_t *voodoo) static uint32_t cmdfifo_get(voodoo_t *voodoo) { uint32_t val; - - while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr) - { - thread_wait_event(voodoo->wake_fifo_thread, -1); - thread_reset_event(voodoo->wake_fifo_thread); - } + + if (!voodoo->cmdfifo_in_sub) { + while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + } + } val = *(uint32_t *)&voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask]; - voodoo->cmdfifo_depth_rd++; + if (!voodoo->cmdfifo_in_sub) + voodoo->cmdfifo_depth_rd++; voodoo->cmdfifo_rp += 4; // voodoo_fifo_log(" CMDFIFO get %08x\n", val); @@ -285,7 +288,7 @@ void voodoo_fifo_thread(void *param) voodoo->time += end_time - start_time; } - while (voodoo->cmdfifo_enabled && voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) + while (voodoo->cmdfifo_enabled && (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr || voodoo->cmdfifo_in_sub)) { uint64_t start_time = plat_timer_read(); uint64_t end_time; @@ -308,6 +311,18 @@ void voodoo_fifo_thread(void *param) case 0: /*NOP*/ break; + case 1: /*JSR*/ +// voodoo_fifo_log("JSR %08x\n", (header >> 4) & 0xfffffc); + voodoo->cmdfifo_ret_addr = voodoo->cmdfifo_rp; + voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; + voodoo->cmdfifo_in_sub = 1; + break; + + case 2: /*RET*/ + voodoo->cmdfifo_rp = voodoo->cmdfifo_ret_addr; + voodoo->cmdfifo_in_sub = 0; + break; + case 3: /*JMP local frame buffer*/ voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; // voodoo_fifo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); From 3b79690e5094e71e1e6b8b7c4f870698858af26d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 21 Nov 2020 16:48:21 +0100 Subject: [PATCH 33/67] Converted the uint32_t cd vol variables to double variables, fixes cd audio scramble using the ad1848 core. --- src/include/86box/snd_ad1848.h | 2 +- src/sound/snd_ad1848.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index 82a7721f3..b6782c139 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -15,7 +15,7 @@ typedef struct ad1848_t int16_t out_l, out_r; - uint32_t cd_vol_l, cd_vol_r; + double cd_vol_l, cd_vol_r; int enable; diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 6f2656ff8..a4595595a 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -16,7 +16,7 @@ #define CS4231 0x80 static int ad1848_vols_6bits[64]; -static uint32_t ad1848_vols_5bits_aux_gain[32]; +static double ad1848_vols_5bits_aux_gain[32]; void ad1848_setirq(ad1848_t *ad1848, int irq) @@ -224,11 +224,11 @@ static void ad1848_poll(void *p) static void ad1848_filter_cd_audio(int channel, double *buffer, void *p) { ad1848_t *ad1848 = (ad1848_t *)p; - int32_t c; - uint32_t volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; + double c; + double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; - c = (((int32_t) *buffer) * volume) >> 16; - *buffer = (double) c; + c = ((*buffer) * volume) / 65536.0; + *buffer = c; } void ad1848_init(ad1848_t *ad1848, int type) @@ -292,7 +292,7 @@ void ad1848_init(ad1848_t *ad1848, int type) attenuation = pow(10, attenuation / 10); - ad1848_vols_5bits_aux_gain[c] = (int)(attenuation * 65536); + ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); } ad1848->type = type; From 7684e177a04a7d5a8712287cf7ae2bdf24ea6194 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 21 Nov 2020 17:20:03 +0100 Subject: [PATCH 34/67] Fixed the cd audio scramble of the ad1848 core used by WSS and the Aztech cards. --- src/include/86box/snd_ad1848.h | 2 +- src/sound/snd_ad1848.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index 82a7721f3..b6782c139 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -15,7 +15,7 @@ typedef struct ad1848_t int16_t out_l, out_r; - uint32_t cd_vol_l, cd_vol_r; + double cd_vol_l, cd_vol_r; int enable; diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 6f2656ff8..a4595595a 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -16,7 +16,7 @@ #define CS4231 0x80 static int ad1848_vols_6bits[64]; -static uint32_t ad1848_vols_5bits_aux_gain[32]; +static double ad1848_vols_5bits_aux_gain[32]; void ad1848_setirq(ad1848_t *ad1848, int irq) @@ -224,11 +224,11 @@ static void ad1848_poll(void *p) static void ad1848_filter_cd_audio(int channel, double *buffer, void *p) { ad1848_t *ad1848 = (ad1848_t *)p; - int32_t c; - uint32_t volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; + double c; + double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; - c = (((int32_t) *buffer) * volume) >> 16; - *buffer = (double) c; + c = ((*buffer) * volume) / 65536.0; + *buffer = c; } void ad1848_init(ad1848_t *ad1848, int type) @@ -292,7 +292,7 @@ void ad1848_init(ad1848_t *ad1848, int type) attenuation = pow(10, attenuation / 10); - ad1848_vols_5bits_aux_gain[c] = (int)(attenuation * 65536); + ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536); } ad1848->type = type; From ceb6ac4c659c812982d59d6e2455e529542cf001 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 21 Nov 2020 16:48:21 +0100 Subject: [PATCH 35/67] Converted the uint32_t cd vol variables to double variables, fixes cd audio scramble using the ad1848 core. From 66e0c0f7ffb38a413dd2ffbeab3f9cb65f54edd8 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 21 Nov 2020 19:22:31 +0100 Subject: [PATCH 36/67] Fixed muted cd audio on the WSS side of the AD1848 core. --- src/sound/snd_ad1848.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index a4595595a..be11e09ca 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -299,5 +299,6 @@ void ad1848_init(ad1848_t *ad1848, int type) timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); - sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); + if (ad1848->type != AD1848_TYPE_DEFAULT) + sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); } From 84c573490cfdcf2be72f3b6f0e6891cdbe02788e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Sat, 21 Nov 2020 19:17:06 +0100 Subject: [PATCH 37/67] Add an option to disable the settings save dialog --- src/config.c | 6 ++++++ src/include/86box/86box.h | 3 ++- src/pc.c | 3 ++- src/win/win_settings.c | 8 +++++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/config.c b/src/config.c index af970cae5..64641bef4 100644 --- a/src/config.c +++ b/src/config.c @@ -487,6 +487,7 @@ load_general(void) confirm_reset = config_get_int(cat, "confirm_reset", 1); confirm_exit = config_get_int(cat, "confirm_exit", 1); + confirm_save = config_get_int(cat, "confirm_save", 1); #ifdef USE_LANGUAGE /* @@ -1760,6 +1761,11 @@ save_general(void) else config_delete_var(cat, "confirm_exit"); + if (confirm_save != 1) + config_set_int(cat, "confirm_save", confirm_save); + else + config_delete_var(cat, "confirm_save"); + #ifdef USE_LANGUAGE if (plat_langid == 0x0409) config_delete_var(cat, "language"); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index b8118d4f0..2ddd11021 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -111,7 +111,8 @@ extern int network_card; /* (C) net interface num */ extern char network_host[522]; /* (C) host network intf */ extern int hdd_format_type; /* (C) hard disk file format */ extern int confirm_reset, /* (C) enable reset confirmation */ - confirm_exit; /* (C) enable exit confirmation */ + confirm_exit, /* (C) enable exit confirmation */ + confirm_save; /* (C) enable save confirmation */ #ifdef USE_DISCORD extern int enable_discord; /* (C) enable Discord integration */ #endif diff --git a/src/pc.c b/src/pc.c index 9276ad255..1f25eba14 100644 --- a/src/pc.c +++ b/src/pc.c @@ -141,7 +141,8 @@ int cpu_use_dynarec = 0, /* (C) cpu uses/needs Dyna */ fpu_type = 0; /* (C) fpu type */ int time_sync = 0; /* (C) enable time sync */ int confirm_reset = 1, /* (C) enable reset confirmation */ - confirm_exit = 1; /* (C) enable exit confirmation */ + confirm_exit = 1, /* (C) enable exit confirmation */ + confirm_save = 1; /* (C) enable save confirmation */ #ifdef USE_DISCORD int enable_discord = 0; /* (C) enable Discord integration */ #endif diff --git a/src/win/win_settings.c b/src/win/win_settings.c index bd06279ae..e51d7176e 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -531,7 +531,13 @@ settings_msgbox_reset() h = hwndMain; hwndMain = hwndParentDialog; - i = ui_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, (wchar_t *) IDS_2123, NULL, NULL); + if (confirm_save) + i = ui_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING | MBX_DONTASK, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, (wchar_t *) IDS_2123, NULL, NULL); + else + i = 0; + + if (i == 10) + confirm_save = 0; hwndMain = h; From 7956a462dc2883987ddf41c18b6c532f587bdde8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Sat, 21 Nov 2020 19:28:58 +0100 Subject: [PATCH 38/67] Refactored the save settings dialog --- src/win/win_settings.c | 49 ++++++++++++------------------------------ 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index e51d7176e..b54315cfe 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -519,38 +519,6 @@ win_settings_changed(void) } -static int -settings_msgbox_reset() -{ - int changed, i = 0; - HWND h; - - changed = win_settings_changed(); - - if (changed) { - h = hwndMain; - hwndMain = hwndParentDialog; - - if (confirm_save) - i = ui_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING | MBX_DONTASK, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, (wchar_t *) IDS_2123, NULL, NULL); - else - i = 0; - - if (i == 10) - confirm_save = 0; - - hwndMain = h; - - if (i == 1) return(1); /* no */ - - if (i == -1) return(0); /* cancel */ - - return(2); /* yes */ - } else - return(1); -} - - /* This saves the settings back to the global variables. */ static void win_settings_save(void) @@ -4982,10 +4950,21 @@ win_settings_confirm(HWND hdlg) int i; SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); - i = settings_msgbox_reset(); - if (i > 0) { - if (i == 2) + + if (win_settings_changed()) { + if (confirm_save) + i = settings_msgbox_ex(MBX_QUESTION_OK | MBX_WARNING | MBX_DONTASK, (wchar_t *) IDS_2121, (wchar_t *) IDS_2122, (wchar_t *) IDS_2123, NULL, NULL); + else + i = 0; + + if (i == 10) { + confirm_save = 0; + i = 0; + } + + if (i == 0) { win_settings_save(); + } DestroyWindow(hwndChildDialog); EndDialog(hdlg, 0); From 9159e523491ede4d8e5425a1c2d6389400610f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Sat, 21 Nov 2020 21:16:32 +0100 Subject: [PATCH 39/67] Fix the settings OK button logic --- src/win/win_settings.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index b54315cfe..ed030243c 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -4964,15 +4964,16 @@ win_settings_confirm(HWND hdlg) if (i == 0) { win_settings_save(); - } - DestroyWindow(hwndChildDialog); - EndDialog(hdlg, 0); - win_notify_dlg_closed(); + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + win_notify_dlg_closed(); - return TRUE; + return TRUE; + } else + return FALSE; } else - return FALSE; + return TRUE; } From ddbc022ce1d87b33fb586a4989ad92f5c018c729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Sat, 21 Nov 2020 21:31:42 +0100 Subject: [PATCH 40/67] Fix Settings dialog not closing after pressing OK --- src/win/win_settings.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index ed030243c..31bdfe8b1 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -4962,18 +4962,16 @@ win_settings_confirm(HWND hdlg) i = 0; } - if (i == 0) { + if (i == 0) win_settings_save(); - - DestroyWindow(hwndChildDialog); - EndDialog(hdlg, 0); - win_notify_dlg_closed(); - - return TRUE; - } else + else return FALSE; - } else - return TRUE; + } + + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + win_notify_dlg_closed(); + return TRUE; } From 252019d846fb19598e71831387379e15b59a98d2 Mon Sep 17 00:00:00 2001 From: sards3 Date: Sat, 21 Nov 2020 16:18:35 -0600 Subject: [PATCH 41/67] Add new hard disk dialog: fix broken CHS when changing back from diff image type --- src/win/win_settings.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/win/win_settings.c b/src/win/win_settings.c index fe435803f..b38d9e315 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -3278,14 +3278,20 @@ hdd_add_file_open_error: if (!wcscmp(text_buf, L"(N/A)")) { settings_enable_window(hdlg, IDC_EDIT_HD_SPT, TRUE); set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, 17); + spt = 17; settings_enable_window(hdlg, IDC_EDIT_HD_HPC, TRUE); set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, 15); + hpc = 15; settings_enable_window(hdlg, IDC_EDIT_HD_CYL, TRUE); set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, 1023); + tracks = 1023; settings_enable_window(hdlg, IDC_EDIT_HD_SIZE, TRUE); set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) ((uint64_t)17 * 15 * 1023 * 512 >> 20)); - settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, TRUE); + size = (uint64_t)17 * 15 * 1023 * 512; + + settings_reset_content(hdlg, IDC_COMBO_HD_TYPE); hdconf_initialize_hdt_combo(hdlg); + settings_enable_window(hdlg, IDC_COMBO_HD_TYPE, TRUE); } } no_update = 0; From 55c620710ca89d249d0bddf7819ad97d467ce58b Mon Sep 17 00:00:00 2001 From: Panagiotis <58827426+tiseno100@users.noreply.github.com> Date: Tue, 24 Nov 2020 23:44:27 +0200 Subject: [PATCH 42/67] Injected a new AMI MSR Injected an AMI MSR used by RC440BX and potentially other Intel AMI boards. --- src/cpu/cpu.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index d434b4e29..d2883dfa9 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -61,7 +61,7 @@ #endif #include "x87_timings.h" - +#define ENABLE_CPU_LOG 1 #define CCR1_USE_SMI (1 << 1) #define CCR1_SMAC (1 << 2) #define CCR1_SM3 (1 << 7) @@ -238,6 +238,7 @@ uint64_t ecx1002ff_msr = 0; /* Some weird long MSR's used by i686 AMI & some Phoenix BIOSes */ uint64_t ecxf0f00250_msr = 0; uint64_t ecxf0f00258_msr = 0; +uint64_t ecxf0f00259_msr = 0; uint64_t star = 0; /* AMD K6-2+. */ @@ -3180,6 +3181,10 @@ void cpu_RDMSR() EAX = ecxf0f00258_msr & 0xffffffff; EDX = ecxf0f00258_msr >> 32; break; + case 0xf0f00259: + EAX = ecxf0f00259_msr & 0xffffffff; + EDX = ecxf0f00259_msr >> 32; + break; default: i686_invalid_rdmsr: cpu_log("RDMSR: Invalid MSR: %08X\n", ECX); @@ -3657,6 +3662,9 @@ void cpu_WRMSR() case 0xf0f00258: ecxf0f00258_msr = EAX | ((uint64_t)EDX << 32); break; + case 0xf0f00259: + ecxf0f00259_msr = EAX | ((uint64_t)EDX << 32); + break; default: i686_invalid_wrmsr: cpu_log("WRMSR: Invalid MSR: %08X\n", ECX); From 1882dfa1c5a1ae2e50b045bb79d182249d52bf62 Mon Sep 17 00:00:00 2001 From: Panagiotis <58827426+tiseno100@users.noreply.github.com> Date: Tue, 24 Nov 2020 23:45:11 +0200 Subject: [PATCH 43/67] Disabled CPU logging --- src/cpu/cpu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index d2883dfa9..a54bd0b9e 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -61,7 +61,6 @@ #endif #include "x87_timings.h" -#define ENABLE_CPU_LOG 1 #define CCR1_USE_SMI (1 << 1) #define CCR1_SMAC (1 << 2) #define CCR1_SM3 (1 << 7) From d6fcf4f683f83035b7f7e33ae0ceadfc7f1a6a23 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 25 Nov 2020 23:33:46 +0100 Subject: [PATCH 44/67] Ported the latest PCem changes (Voodoo and ATI 28800). --- src/include/86box/vid_voodoo_codegen_x86-64.h | 42 +++++++++++++++++-- src/include/86box/vid_voodoo_codegen_x86.h | 42 +++++++++++++++++-- src/video/vid_ati28800.c | 10 +---- src/video/vid_voodoo_banshee.c | 23 +++++++++- 4 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/include/86box/vid_voodoo_codegen_x86-64.h b/src/include/86box/vid_voodoo_codegen_x86-64.h index b5e3ed6d1..bbc7d2537 100644 --- a/src/include/86box/vid_voodoo_codegen_x86-64.h +++ b/src/include/86box/vid_voodoo_codegen_x86-64.h @@ -1733,10 +1733,44 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & FBZ_CHROMAKEY)) { - addbyte(0x66); /*MOVD EAX, XMM0*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0xc0); + switch (_rgb_sel) + { + case CC_LOCALSELECT_ITER_RGB: + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + case CC_LOCALSELECT_COLOR1: + addbyte(0x8b); /*MOV EAX, params->color1[RSI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + break; + case CC_LOCALSELECT_TEX: + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + } addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, chromaKey)); diff --git a/src/include/86box/vid_voodoo_codegen_x86.h b/src/include/86box/vid_voodoo_codegen_x86.h index a9f2c5533..6e8c891c1 100644 --- a/src/include/86box/vid_voodoo_codegen_x86.h +++ b/src/include/86box/vid_voodoo_codegen_x86.h @@ -1668,10 +1668,44 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & FBZ_CHROMAKEY)) { - addbyte(0x66); /*MOVD EAX, XMM0*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0xc0); + switch (_rgb_sel) + { + case CC_LOCALSELECT_ITER_RGB: + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + case CC_LOCALSELECT_COLOR1: + addbyte(0x8b); /*MOV EAX, params->color1[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + break; + case CC_LOCALSELECT_TEX: + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + } addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, chromaKey)); diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index b1a1c8222..5dcca426a 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -401,7 +401,7 @@ ati28800_recalctimings(svga_t *svga) case 0x09: svga->clock = (cpuclock * (double)(1ull << 32)) / 32000000.0; break; case 0x0A: svga->clock = (cpuclock * (double)(1ull << 32)) / 37500000.0; break; case 0x0B: svga->clock = (cpuclock * (double)(1ull << 32)) / 39000000.0; break; - case 0x0C: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 0x0C: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break; case 0x0D: svga->clock = (cpuclock * (double)(1ull << 32)) / 56644000.0; break; case 0x0E: svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; break; case 0x0F: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; @@ -423,14 +423,6 @@ ati28800_recalctimings(svga_t *svga) svga->rowoffset <<= 1; } - if (svga->crtc[0x17] & 4) { - svga->vtotal <<= 1; - svga->dispend <<= 1; - svga->vsyncstart <<= 1; - svga->split <<= 1; - svga->vblankstart <<= 1; - } - if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) { /* Extended 256 colour modes */ switch (svga->bpp) { case 8: diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index ba4964a09..932fb9ee6 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -660,7 +660,7 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) case Video_hwCurPatAddr: banshee->hwCurPatAddr = val; - svga->hwcursor.addr = val & 0xfffff0; + svga->hwcursor.addr = (val & 0xfffff0) + (svga->hwcursor.yoff * 16); break; case Video_hwCurLoc: banshee->hwCurLoc = val; @@ -673,6 +673,7 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) } else svga->hwcursor.yoff = 0; + svga->hwcursor.addr = (banshee->hwCurPatAddr & 0xfffff0) + (svga->hwcursor.yoff * 16); svga->hwcursor.xsize = 64; svga->hwcursor.ysize = 64; // banshee_log("hwCurLoc %08x %i\n", val, svga->hwcursor.y); @@ -1381,6 +1382,9 @@ static uint16_t banshee_read_linear_w(uint32_t addr, void *p) voodoo_t *voodoo = banshee->voodoo; svga_t *svga = &banshee->svga; + if (addr & 1) + return banshee_read_linear(addr, p) | (banshee_read_linear(addr+1, p) << 8); + sub_cycles(voodoo->read_time); addr &= svga->decode_mask; @@ -1412,6 +1416,9 @@ static uint32_t banshee_read_linear_l(uint32_t addr, void *p) voodoo_t *voodoo = banshee->voodoo; svga_t *svga = &banshee->svga; + if (addr & 3) + return banshee_read_linear_w(addr, p) | (banshee_read_linear_w(addr+2, p) << 16); + sub_cycles(voodoo->read_time); addr &= svga->decode_mask; @@ -1475,6 +1482,13 @@ static void banshee_write_linear_w(uint32_t addr, uint16_t val, void *p) voodoo_t *voodoo = banshee->voodoo; svga_t *svga = &banshee->svga; + if (addr & 1) + { + banshee_write_linear(addr, val, p); + banshee_write_linear(addr + 1, val >> 8, p); + return; + } + sub_cycles(voodoo->write_time); // banshee_log("write_linear: addr=%08x val=%02x\n", addr, val); @@ -1508,6 +1522,13 @@ static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p) svga_t *svga = &banshee->svga; int timing; + if (addr & 3) + { + banshee_write_linear_w(addr, val, p); + banshee_write_linear_w(addr + 2, val >> 16, p); + return; + } + if (addr == voodoo->last_write_addr+4) timing = voodoo->burst_time; else From 6e233f4ac8785160ca1cea9996b8ee80825c45a1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 26 Nov 2020 18:20:24 +0100 Subject: [PATCH 45/67] SDL renderer improvements and fixes and added SDL OpenGL option; Various performance improvements; Fixed USB UHCI HCHalt; Cirrus Logic CL-GD 5422/24 fixes and removed them from the Dev branch; The Storage controllers sections of Settings now has its own corresponding section of the configuration file; Fixed the AT clock divisors for some Pentium OverDrive CPU's; Added the ACPI RTC status (no ACPI RTC alarm event yet). --- src/acpi.c | 68 +++++++++++++++--- src/chipset/intel_sio.c | 4 +- src/config.c | 125 ++++++++++++++++++++++++++------- src/cpu/808x.c | 17 +++++ src/cpu/cpu_table.c | 4 +- src/device/isartc.c | 4 +- src/device/keyboard_at.c | 2 +- src/device/mouse_serial.c | 1 - src/device/serial.c | 4 +- src/disk/hdc_xtide.c | 2 +- src/floppy/fdc.c | 4 +- src/floppy/fdd.c | 2 +- src/game/gameport.c | 4 +- src/include/86box/86box.h | 1 + src/include/86box/acpi.h | 2 + src/include/86box/resource.h | 3 +- src/include/86box/vid_svga.h | 3 +- src/include/86box/video.h | 2 - src/include/86box/win.h | 4 +- src/include/86box/win_sdl.h | 2 + src/io.c | 12 ++-- src/machine/m_amstrad.c | 4 +- src/machine/m_at_t3100e_vid.c | 4 +- src/machine/m_xt_t1000_vid.c | 4 +- src/mem/mem.c | 89 +++++++++++++---------- src/nvr_at.c | 4 +- src/pic.c | 24 +++++-- src/pit.c | 17 +++-- src/sound/snd_opl.c | 4 +- src/sound/snd_sb.c | 2 +- src/usb.c | 6 +- src/video/vid_cga.c | 2 +- src/video/vid_cl54xx.c | 24 +++---- src/video/vid_colorplus.c | 4 +- src/video/vid_ega.c | 4 +- src/video/vid_genius.c | 2 +- src/video/vid_hercules.c | 2 +- src/video/vid_ht216.c | 4 +- src/video/vid_mga.c | 12 ++-- src/video/vid_sigma.c | 4 +- src/video/vid_svga.c | 82 +++++++++++++++------ src/video/vid_table.c | 4 -- src/video/vid_tgui9440.c | 6 +- src/video/vid_voodoo.c | 10 +-- src/video/vid_voodoo_banshee.c | 36 +++++----- src/video/video.c | 18 ++--- src/vnc.c | 2 +- src/win/86Box.rc | 3 +- src/win/Makefile.mingw | 4 -- src/win/win.c | 22 ++++-- src/win/win_sdl.c | 125 +++++++++++++++++++++++++++------ src/win/win_settings.c | 73 +++++++++++++------ src/win/win_ui.c | 26 ++++--- 53 files changed, 618 insertions(+), 279 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index 350021e00..81c62b103 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -39,6 +39,9 @@ #include <86box/i2c.h> +int acpi_rtc_status = 0; + + #ifdef ENABLE_ACPI_LOG int acpi_do_log = ENABLE_ACPI_LOG; @@ -119,6 +122,8 @@ acpi_reg_read_common_regs(int size, uint16_t addr, void *p) case 0x00: case 0x01: /* PMSTS - Power Management Status Register (IO) */ ret = (dev->regs.pmsts >> shift16) & 0xff; + if (addr == 0x01) + ret |= (acpi_rtc_status << 2); break; case 0x02: case 0x03: /* PMEN - Power Management Resume Enable Register (IO) */ @@ -127,6 +132,8 @@ acpi_reg_read_common_regs(int size, uint16_t addr, void *p) case 0x04: case 0x05: /* PMCNTRL - Power Management Control Register (IO) */ ret = (dev->regs.pmcntrl >> shift16) & 0xff; + if (addr == 0x05) + ret = (ret & 0xdf) | 0x02; /* Bit 5 is write-only. */ break; case 0x08: case 0x09: case 0x0a: case 0x0b: /* PMTMR - Power Management Timer Register (IO) */ @@ -138,7 +145,10 @@ acpi_reg_read_common_regs(int size, uint16_t addr, void *p) break; } - acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif return ret; } @@ -211,7 +221,10 @@ acpi_reg_read_intel(int size, uint16_t addr, void *p) break; } - acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif return ret; } @@ -285,7 +298,10 @@ acpi_reg_read_via_common(int size, uint16_t addr, void *p) break; } - acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif return ret; } @@ -338,7 +354,10 @@ acpi_reg_read_via(int size, uint16_t addr, void *p) break; } - acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif return ret; } @@ -372,7 +391,10 @@ acpi_reg_read_via_596b(int size, uint16_t addr, void *p) break; } - acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif return ret; } @@ -386,7 +408,10 @@ acpi_reg_read_smc(int size, uint16_t addr, void *p) ret = acpi_reg_read_common_regs(size, addr, p); - acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret); +#endif return ret; } @@ -436,13 +461,18 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p) int shift16, sus_typ; addr &= 0x3f; - acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); +#endif shift16 = (addr & 1) << 3; switch (addr) { case 0x00: case 0x01: /* PMSTS - Power Management Status Register (IO) */ dev->regs.pmsts &= ~((val << shift16) & 0x8d31); + if ((addr == 0x01) && (val & 0x04)) + acpi_rtc_status = 0; acpi_update_irq(dev); break; case 0x02: case 0x03: @@ -452,8 +482,7 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p) break; case 0x04: case 0x05: /* PMCNTRL - Power Management Control Register (IO) */ - dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3c07; - if (dev->regs.pmcntrl & 0x2000) { + if ((addr == 0x05) && (dev->regs.pmcntrl & 0x2000)) { sus_typ = (dev->regs.pmcntrl >> 10) & 7; switch (sus_typ) { case 0: @@ -479,8 +508,12 @@ acpi_reg_write_common_regs(int size, uint16_t addr, uint8_t val, void *p) resetx86(); break; + default: + dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3c07; + break; } - } + } else + dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3c07; break; } } @@ -493,7 +526,10 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p) int shift16, shift32; addr &= 0x3f; - acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); +#ifdef ENABLE_ACPI_LOG + if (size != 1) + acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); +#endif shift16 = (addr & 1) << 3; shift32 = (addr & 3) << 3; @@ -876,6 +912,8 @@ acpi_reg_read(uint16_t addr, void *p) ret = acpi_reg_read_common(1, addr, p); + acpi_log("ACPI: Read B %02X from %04X\n", ret, addr); + return ret; } @@ -924,6 +962,8 @@ acpi_aux_read_read(uint16_t addr, void *p) static void acpi_reg_writel(uint16_t addr, uint32_t val, void *p) { + acpi_log("ACPI: Write L %08X to %04X\n", val, addr); + acpi_reg_write_common(4, addr, val & 0xff, p); acpi_reg_write_common(4, addr + 1, (val >> 8) & 0xff, p); acpi_reg_write_common(4, addr + 2, (val >> 16) & 0xff, p); @@ -934,6 +974,8 @@ acpi_reg_writel(uint16_t addr, uint32_t val, void *p) static void acpi_reg_writew(uint16_t addr, uint16_t val, void *p) { + acpi_log("ACPI: Write W %04X to %04X\n", val, addr); + acpi_reg_write_common(2, addr, val & 0xff, p); acpi_reg_write_common(2, addr + 1, (val >> 8) & 0xff, p); } @@ -942,6 +984,8 @@ acpi_reg_writew(uint16_t addr, uint16_t val, void *p) static void acpi_reg_write(uint16_t addr, uint8_t val, void *p) { + acpi_log("ACPI: Write B %02X to %04X\n", val, addr); + acpi_reg_write_common(1, addr, val, p); } @@ -1188,6 +1232,8 @@ acpi_reset(void *priv) - Bit 1: 80-conductor cable on primary IDE channel (active low) */ dev->regs.gpi_val = !strcmp(machines[machine].internal_name, "wcf681") ? 0xffffffe3 : 0xffffffe5; } + + acpi_rtc_status = 0; } diff --git a/src/chipset/intel_sio.c b/src/chipset/intel_sio.c index cf587170a..d456c96df 100644 --- a/src/chipset/intel_sio.c +++ b/src/chipset/intel_sio.c @@ -105,7 +105,7 @@ sio_timer_read(uint16_t addr, void *priv) uint8_t ret = 0xff; if (!(addr & 0x0002)) { - sub_cycles((int)(PITCONST >> 32)); + cycles -= ((int) (PITCONST >> 32)); sio_timer_latch = timer_get_remaining_us(&dev->timer); @@ -126,7 +126,7 @@ sio_timer_readw(uint16_t addr, void *priv) uint16_t ret = 0xffff; if (!(addr & 0x0002)) { - sub_cycles((int)(PITCONST >> 32)); + cycles -= ((int) (PITCONST >> 32)); ret = timer_get_remaining_us(&dev->timer); } diff --git a/src/config.c b/src/config.c index 85c9c8d65..a2aa1b19d 100644 --- a/src/config.c +++ b/src/config.c @@ -113,6 +113,7 @@ static list_t config_head; /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ static int backwards_compat = 0; +static int backwards_compat2 = 0; #ifdef ENABLE_CONFIG_LOG @@ -873,14 +874,16 @@ load_ports(void) } -/* Load "Other Peripherals" section. */ +/* Load "Storage Controllers" section. */ static void -load_other_peripherals(void) +load_storage_controllers(void) { - char *cat = "Other peripherals"; + char *cat = "Storage controllers"; char *p; - char temp[512]; - int c, free_p = 0; + int free_p = 0; + + /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ + backwards_compat2 = (find_section(cat) == NULL); p = config_get_string(cat, "scsicard", NULL); if (p != NULL) @@ -921,19 +924,6 @@ load_other_peripherals(void) ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0); ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0); - - bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0); - postcard_enabled = !!config_get_int(cat, "postcard_enabled", 0); - - for (c = 0; c < ISAMEM_MAX; c++) { - sprintf(temp, "isamem%d_type", c); - - p = config_get_string(cat, temp, "none"); - isamem_type[c] = isamem_get_from_internal_name(p); - } - - p = config_get_string(cat, "isartc_type", "none"); - isartc_type = isartc_get_from_internal_name(p); } @@ -1518,7 +1508,6 @@ load_other_removable_devices(void) sprintf(temp, "zip_%02i_iso_path", c+1); config_delete_var(cat, temp); } - memset(temp, 0x00, sizeof(temp)); for (c=0; c cycles) { + cyc_diff = old_cycles - cycles; + cycles = old_cycles; + resub_cycles(cyc_diff); + } +} + + #undef readmemb #undef readmemw #undef readmeml @@ -280,6 +293,8 @@ sub_cycles(int c) static void cpu_io(int bits, int out, uint16_t port) { + int old_cycles = cycles; + if (out) { wait(4, 1); if (bits == 16) { @@ -305,6 +320,8 @@ cpu_io(int bits, int out, uint16_t port) } else AL = inb(port); } + + resub_cycles(old_cycles); } diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 585f85831..3381f400c 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -600,9 +600,9 @@ const cpu_family_t cpu_families[] = { .name = "Pentium OverDrive", .internal_name = "pentium_p54c_od3v", .cpus = { - {"125", CPU_PENTIUM, fpus_internal, 125000000, 3.0, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 12,12,7,7, 16}, + {"125", CPU_PENTIUM, fpus_internal, 125000000, 3.0, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 12,12,7,7, 15}, {"150", CPU_PENTIUM, fpus_internal, 150000000, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 35/2}, - {"166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 40}, + {"166", CPU_PENTIUM, fpus_internal, 166666666, 2.5, 3520, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC | CPU_FIXED_MULTIPLIER, 15,15,7,7, 20}, {"", 0} } }, { diff --git a/src/device/isartc.c b/src/device/isartc.c index a14d7e82d..610bf0eae 100644 --- a/src/device/isartc.c +++ b/src/device/isartc.c @@ -388,7 +388,7 @@ mm67_read(uint16_t port, void *priv) uint8_t ret = 0xff; /* This chip is directly mapped on I/O. */ - sub_cycles(ISA_CYCLES(4)); + cycles -= ISA_CYCLES(4); switch(reg) { case MM67_ISTAT: /* IRQ status (RO) */ @@ -424,7 +424,7 @@ mm67_write(uint16_t port, uint8_t val, void *priv) #endif /* This chip is directly mapped on I/O. */ - sub_cycles(ISA_CYCLES(4)); + cycles -= ISA_CYCLES(4); switch(reg) { case MM67_ISTAT: /* intr status (RO) */ diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index cd521da8b..1164c7007 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2047,7 +2047,7 @@ kbd_read(uint16_t port, void *priv) uint8_t ret = 0xff; if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63)) port = 0x61; diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index 5ae1cd36b..8535e3466 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -173,7 +173,6 @@ sermouse_callback(struct serial_s *serial, void *priv) dev->format = 7; dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); timer_stop(&dev->command_timer); - sub_cycles(ISA_CYCLES(8)); #ifdef USE_NEW_DYNAREC sermouse_timer_on(dev, 5000.0, 0); #else diff --git a/src/device/serial.c b/src/device/serial.c index b331d4d99..ed6915438 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -355,7 +355,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) serial_log("UART: Write %02X to port %02X\n", val, addr); - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); switch (addr & 7) { case 0: @@ -513,7 +513,7 @@ serial_read(uint16_t addr, void *p) serial_t *dev = (serial_t *)p; uint8_t i, ret = 0; - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); switch (addr & 7) { case 0: diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 7dc6ec095..50403d9ae 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -276,7 +276,7 @@ const device_t xtide_acculogic_device = { const device_t xtide_at_ps2_device = { "PS/2 AT XTIDE (1.1.5)", - DEVICE_AT, + DEVICE_ISA | DEVICE_AT, 0, xtide_at_ps2_init, xtide_at_close, NULL, { xtide_at_ps2_available }, NULL, NULL, diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 82191881c..a48307b2f 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -735,7 +735,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_log("Write FDC %04X %02X\n", addr, val); - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); switch (addr&7) { case 0: @@ -1261,7 +1261,7 @@ fdc_read(uint16_t addr, void *priv) uint8_t ret; int drive; - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); switch (addr & 7) { case 0: /* STA */ diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 7e1b21452..ece63c55e 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -552,7 +552,7 @@ fdd_hole(int drive) } -uint64_t +static __inline uint64_t fdd_byteperiod(int drive) { if (!fdd_get_turbo(drive) && drives[drive].byteperiod) diff --git a/src/game/gameport.c b/src/game/gameport.c index d1fc35492..883af2388 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -186,7 +186,7 @@ gameport_write(uint16_t addr, uint8_t val, void *priv) p->joystick->write(p->joystick_dat); - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); } @@ -198,7 +198,7 @@ gameport_read(uint16_t addr, void *priv) ret = p->state | p->joystick->read(p->joystick_dat); - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); return(ret); } diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 2ddd11021..627a293c6 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -177,6 +177,7 @@ extern uint16_t get_last_addr(void); should be in cpu.c but I put it here to avoid having to include cpu.c everywhere. */ extern void sub_cycles(int c); +extern void resub_cycles(int old_cycles); extern double isa_timing; extern int io_delay; diff --git a/src/include/86box/acpi.h b/src/include/86box/acpi.h index 0e5e688ef..6cc98cefb 100644 --- a/src/include/86box/acpi.h +++ b/src/include/86box/acpi.h @@ -89,6 +89,8 @@ typedef struct /* Global variables. */ +extern int acpi_rtc_status; + extern const device_t acpi_intel_device; extern const device_t acpi_smc_device; extern const device_t acpi_via_device; diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index 5b0cbf0c8..24ede722a 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -295,8 +295,9 @@ #define IDM_VID_REMEMBER 40041 #define IDM_VID_SDL_SW 40050 #define IDM_VID_SDL_HW 40051 +#define IDM_VID_SDL_OPENGL 40052 #ifdef USE_VNC -#define IDM_VID_VNC 40052 +#define IDM_VID_VNC 40053 #endif #define IDM_VID_SCALE_1X 40055 #define IDM_VID_SCALE_2X 40056 diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 9e4277789..ca7ae4c21 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -20,7 +20,8 @@ #define FLAG_EXTRA_BANKS 1 #define FLAG_ADDR_BY8 2 -#define FLAG_LATCH8 4 +#define FLAG_EXT_WRITE 4 +#define FLAG_LATCH8 8 typedef struct { diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 8997d3857..6640827ce 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -214,10 +214,8 @@ extern const device_t gd5401_isa_device; extern const device_t gd5402_isa_device; extern const device_t gd5402_onboard_device; extern const device_t gd5420_isa_device; -#if defined(DEV_BRANCH) && defined(USE_CL5422) extern const device_t gd5422_isa_device; extern const device_t gd5424_vlb_device; -#endif extern const device_t gd5426_vlb_device; extern const device_t gd5426_onboard_device; extern const device_t gd5428_isa_device; diff --git a/src/include/86box/win.h b/src/include/86box/win.h index 75c250ddb..4aceae0be 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -83,9 +83,9 @@ DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); #define WM_HAS_SHUTDOWN 0x8897 #ifdef USE_VNC -#define RENDERERS_NUM 3 +#define RENDERERS_NUM 4 #else -#define RENDERERS_NUM 2 +#define RENDERERS_NUM 3 #endif diff --git a/src/include/86box/win_sdl.h b/src/include/86box/win_sdl.h index 97ee42090..4f6bca231 100644 --- a/src/include/86box/win_sdl.h +++ b/src/include/86box/win_sdl.h @@ -53,8 +53,10 @@ extern void sdl_close(void); extern int sdl_inits(HWND h); extern int sdl_inith(HWND h); +extern int sdl_initho(HWND h); extern int sdl_inits_fs(HWND h); extern int sdl_inith_fs(HWND h); +extern int sdl_initho_fs(HWND h); extern int sdl_pause(void); extern void sdl_resize(int x, int y); extern void sdl_enable(int enable); diff --git a/src/io.c b/src/io.c index daea584c4..0930da37d 100644 --- a/src/io.c +++ b/src/io.c @@ -307,7 +307,7 @@ inb(uint16_t port) amstrad_latch = AMSTRAD_SW9; if (!found) - sub_cycles(io_delay); + cycles -= io_delay; io_log("[%04X:%08X] (%i, %i, %04i) in b(%04X) = %02X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); @@ -334,7 +334,7 @@ outb(uint16_t port, uint8_t val) } if (!found) { - sub_cycles(io_delay); + cycles -= io_delay; #ifdef USE_DYNAREC if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed))) update_tsc(); @@ -392,7 +392,7 @@ inw(uint16_t port) amstrad_latch = AMSTRAD_SW9; if (!found) - sub_cycles(io_delay); + cycles -= io_delay; io_log("[%04X:%08X] (%i, %i, %04i) in w(%04X) = %04X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); @@ -433,7 +433,7 @@ outw(uint16_t port, uint16_t val) } if (!found) { - sub_cycles(io_delay); + cycles -= io_delay; #ifdef USE_DYNAREC if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed))) update_tsc(); @@ -510,7 +510,7 @@ inl(uint16_t port) amstrad_latch = AMSTRAD_SW9; if (!found) - sub_cycles(io_delay); + cycles -= io_delay; io_log("[%04X:%08X] (%i, %i, %04i) in l(%04X) = %08X\n", CS, cpu_state.pc, in_smm, found, qfound, port, ret); @@ -566,7 +566,7 @@ outl(uint16_t port, uint32_t val) } if (!found) { - sub_cycles(io_delay); + cycles -= io_delay; #ifdef USE_DYNAREC if (cpu_use_dynarec && ((port == 0xeb) || (port == 0xed))) update_tsc(); diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index bc22e11f9..87de506ef 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -301,7 +301,7 @@ vid_write_1512(uint32_t addr, uint8_t val, void *priv) amsvid_t *vid = (amsvid_t *)priv; egawrites++; - sub_cycles(12); + cycles -= 12; addr &= 0x3fff; if ((vid->cgamode & 0x12) == 0x12) { @@ -320,7 +320,7 @@ vid_read_1512(uint32_t addr, void *priv) amsvid_t *vid = (amsvid_t *)priv; egareads++; - sub_cycles(12); + cycles -= 12; addr &= 0x3fff; if ((vid->cgamode & 0x12) == 0x12) diff --git a/src/machine/m_at_t3100e_vid.c b/src/machine/m_at_t3100e_vid.c index 1f27b7392..945b6b296 100644 --- a/src/machine/m_at_t3100e_vid.c +++ b/src/machine/m_at_t3100e_vid.c @@ -204,7 +204,7 @@ void t3100e_write(uint32_t addr, uint8_t val, void *p) egawrites++; t3100e->vram[addr & 0x7fff] = val; - sub_cycles(4); + cycles -= 4; } @@ -213,7 +213,7 @@ uint8_t t3100e_read(uint32_t addr, void *p) { t3100e_t *t3100e = (t3100e_t *)p; egareads++; - sub_cycles(4); + cycles -= 4; return t3100e->vram[addr & 0x7fff]; } diff --git a/src/machine/m_xt_t1000_vid.c b/src/machine/m_xt_t1000_vid.c index 15a9f699c..2f291ab63 100644 --- a/src/machine/m_xt_t1000_vid.c +++ b/src/machine/m_xt_t1000_vid.c @@ -194,14 +194,14 @@ static void t1000_write(uint32_t addr, uint8_t val, void *p) egawrites++; t1000->vram[addr & 0x3fff] = val; - sub_cycles(4); + cycles -= 4; } static uint8_t t1000_read(uint32_t addr, void *p) { t1000_t *t1000 = (t1000_t *)p; egareads++; - sub_cycles(4); + cycles -= 4; return t1000->vram[addr & 0x3fff]; } diff --git a/src/mem/mem.c b/src/mem/mem.c index ee92d995c..52fae564d 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -273,7 +273,7 @@ mem_flush_write_page(uint32_t addr, uint32_t virt) #define rammap(x) ((uint32_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 2) & MEM_GRANULARITY_QMASK] #define rammap64(x) ((uint64_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 3) & MEM_GRANULARITY_PMASK] -static uint64_t +static __inline uint64_t mmutranslatereal_normal(uint32_t addr, int rw) { uint32_t temp,temp2,temp3; @@ -335,7 +335,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) } -static uint64_t +static __inline uint64_t mmutranslatereal_pae(uint32_t addr, int rw) { uint64_t temp,temp2,temp3,temp4; @@ -428,7 +428,7 @@ mmutranslatereal32(uint32_t addr, int rw) } -static uint64_t +static __inline uint64_t mmutranslate_noabrt_normal(uint32_t addr, int rw) { uint32_t temp,temp2,temp3; @@ -461,7 +461,7 @@ mmutranslate_noabrt_normal(uint32_t addr, int rw) } -static uint64_t +static __inline uint64_t mmutranslate_noabrt_pae(uint32_t addr, int rw) { uint64_t temp,temp2,temp3,temp4; @@ -571,7 +571,7 @@ addreadlookup(uint32_t virt, uint32_t phys) readlookup[readlnext++] = virt >> 12; readlnext &= (cachesize-1); - sub_cycles(9); + cycles -= 9; } @@ -624,7 +624,7 @@ addwritelookup(uint32_t virt, uint32_t phys) writelookup[writelnext++] = virt >> 12; writelnext &= (cachesize - 1); - sub_cycles(9); + cycles -= 9; } @@ -664,15 +664,19 @@ uint8_t read_mem_b(uint32_t addr) { mem_mapping_t *map; + uint8_t ret = 0xff; + int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; map = read_mapping[addr >> MEM_GRANULARITY_BITS]; if (map && map->read_b) - return map->read_b(addr, map->p); + ret = map->read_b(addr, map->p); - return 0xff; + resub_cycles(old_cycles); + + return ret; } @@ -680,22 +684,26 @@ uint16_t read_mem_w(uint32_t addr) { mem_mapping_t *map; + uint16_t ret = 0xffff; + int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; if (addr & 1) - return read_mem_b(addr) | (read_mem_b(addr + 1) << 8); + ret = read_mem_b(addr) | (read_mem_b(addr + 1) << 8); + else { + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; - map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_w) + ret = map->read_w(addr, map->p); + else if (map && map->read_b) + ret = map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8); + } - if (map && map->read_w) - return map->read_w(addr, map->p); + resub_cycles(old_cycles); - if (map && map->read_b) - return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8); - - return 0xffff; + return ret; } @@ -703,6 +711,7 @@ void write_mem_b(uint32_t addr, uint8_t val) { mem_mapping_t *map; + int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -710,6 +719,8 @@ write_mem_b(uint32_t addr, uint8_t val) map = write_mapping[addr >> MEM_GRANULARITY_BITS]; if (map && map->write_b) map->write_b(addr, val, map->p); + + resub_cycles(old_cycles); } @@ -717,6 +728,7 @@ void write_mem_w(uint32_t addr, uint16_t val) { mem_mapping_t *map; + int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -724,18 +736,19 @@ write_mem_w(uint32_t addr, uint16_t val) if (addr & 1) { write_mem_b(addr, val); write_mem_b(addr + 1, val >> 8); - return; - } - - map = write_mapping[addr >> MEM_GRANULARITY_BITS]; - if (map) { - if (map->write_w) - map->write_w(addr, val, map->p); - else if (map->write_b) { - map->write_b(addr, val, map->p); - map->write_b(addr + 1, val >> 8, map->p); + } else { + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + if (map->write_w) + map->write_w(addr, val, map->p); + else if (map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + } } } + + resub_cycles(old_cycles); } @@ -802,7 +815,7 @@ readmemwl(uint32_t addr) if (addr64 & 1) { if (!cpu_cyrix_alignment || (addr64 & 7) == 7) - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr64 & 0xfff) > 0xffe) { if (cr0 >> 31) { if (mmutranslate_read(addr) == 0xffffffffffffffffULL) @@ -846,7 +859,7 @@ writememwl(uint32_t addr, uint16_t val) if (addr & 1) { if (!cpu_cyrix_alignment || (addr & 7) == 7) - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr & 0xFFF) > 0xFFE) { if (cr0 >> 31) { if (mmutranslate_write(addr) == 0xffffffff) @@ -899,7 +912,7 @@ readmemll(uint32_t addr) if (addr & 3) { if (!cpu_cyrix_alignment || (addr & 7) > 4) - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr & 0xfff) > 0xffc) { if (cr0>>31) { if (mmutranslate_read(addr) == 0xffffffffffffffffULL) @@ -949,7 +962,7 @@ writememll(uint32_t addr, uint32_t val) if (addr & 3) { if (!cpu_cyrix_alignment || (addr & 7) > 4) - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr & 0xFFF) > 0xFFC) { if (cr0>>31) { if (mmutranslate_write(addr) == 0xffffffffffffffffULL) @@ -1005,7 +1018,7 @@ readmemql(uint32_t addr) mem_logical_addr = addr; if (addr & 7) { - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr & 0xFFF) > 0xFF8) { if (cr0>>31) { if (mmutranslate_read(addr) == 0xffffffffffffffffULL) @@ -1045,7 +1058,7 @@ writememql(uint32_t addr, uint64_t val) mem_logical_addr = addr; if (addr & 7) { - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr & 0xFFF) > 0xFF8) { if (cr0>>31) { if (mmutranslate_write(addr) == 0xffffffffffffffffULL) @@ -1122,7 +1135,7 @@ readmemwl(uint32_t seg, uint32_t addr) if (addr2 & 1) { if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr2 & 0xfff) > 0xffe) { if (cr0 >> 31) { if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) @@ -1174,7 +1187,7 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) if (addr2 & 1) { if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr2 & 0xFFF) > 0xffe) { if (cr0 >> 31) { if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; @@ -1234,7 +1247,7 @@ readmemll(uint32_t seg, uint32_t addr) if (addr2 & 3) { if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr2 & 0xfff) > 0xffc) { if (cr0 >> 31) { if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) return 0xffffffff; @@ -1284,7 +1297,7 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) if (addr2 & 3) { if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr2 & 0xfff) > 0xffc) { if (cr0 >> 31) { if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; @@ -1344,7 +1357,7 @@ readmemql(uint32_t seg, uint32_t addr) uint32_t addr2 = mem_logical_addr = seg + addr; if (addr2 & 7) { - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr2 & 0xfff) > 0xff8) { if (cr0 >> 31) { if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) return 0xffffffffffffffffULL; @@ -1382,7 +1395,7 @@ writememql(uint32_t seg, uint32_t addr, uint64_t val) uint32_t addr2 = mem_logical_addr = seg + addr; if (addr2 & 7) { - sub_cycles(timing_misaligned); + cycles -= timing_misaligned; if ((addr2 & 0xfff) > 0xff8) { if (cr0 >> 31) { if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; diff --git a/src/nvr_at.c b/src/nvr_at.c index 1b5612593..e7a3f7f4e 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -638,7 +638,7 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) local_t *local = (local_t *)nvr->data; uint8_t addr_id = (addr & 0x0e) >> 1; - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); if (local->bank[addr_id] == 0xff) return; @@ -673,7 +673,7 @@ nvr_read(uint16_t addr, void *priv) uint8_t addr_id = (addr & 0x0e) >> 1; uint16_t i, checksum = 0x0000; - sub_cycles(ISA_CYCLES(8)); + cycles -= ISA_CYCLES(8); if (/* (addr & 1) && */(local->bank[addr_id] == 0xff)) return 0xff; diff --git a/src/pic.c b/src/pic.c index ad2efc67e..418f4e03a 100644 --- a/src/pic.c +++ b/src/pic.c @@ -31,6 +31,10 @@ #include <86box/pic.h> #include <86box/timer.h> #include <86box/pit.h> +#include <86box/device.h> +#include <86box/apm.h> +#include <86box/nvr.h> +#include <86box/acpi.h> enum @@ -142,7 +146,7 @@ pic_cascade_mode(pic_t *dev) } -static uint8_t +static __inline uint8_t pic_slave_on(pic_t *dev, int channel) { pic_log("pic_slave_on(%i): %i, %02X, %02X\n", channel, pic_cascade_mode(dev), dev->icw4 & 0x0c, dev->icw3 & (1 << channel)); @@ -152,7 +156,7 @@ pic_slave_on(pic_t *dev, int channel) } -static int +static __inline int find_best_interrupt(pic_t *dev) { uint8_t b, s; @@ -184,7 +188,7 @@ find_best_interrupt(pic_t *dev) } -void +static __inline void pic_update_pending(void) { int is_at = IS_ARCH(machine, (MACHINE_BUS_ISA16 | MACHINE_BUS_MCA | MACHINE_BUS_PCMCIA)); @@ -321,7 +325,7 @@ pic_action(pic_t *dev, uint8_t irq, uint8_t eoi, uint8_t rotate) /* Automatic non-specific EOI. */ -static void +static __inline void pic_auto_non_specific_eoi(pic_t *dev) { uint8_t irq; @@ -520,6 +524,9 @@ picint_common(uint16_t num, int level, int set) return; } + if (num & 0x0100) + acpi_rtc_status = !!set; + if (set) { if (num & 0xff00) { if (level) @@ -650,8 +657,13 @@ picinterrupt() pit_ctr_set_gate(&pit2->counters[0], 0); /* Two ACK's - do them in a loop to avoid potential compiler misoptimizations. */ - for (i = 0; i < 2; i++) - ret = pic_irq_ack(); + for (i = 0; i < 2; i++) { + ret = pic_irq_ack_read(&pic, pic.ack_bytes); + pic.ack_bytes = (pic.ack_bytes + 1) % (pic_i86_mode(&pic) ? 2 : 3); + + if (pic.ack_bytes == 0) + pic_update_pending(); + } } return ret; diff --git a/src/pit.c b/src/pit.c index 03fd80c93..2e10a7b38 100644 --- a/src/pit.c +++ b/src/pit.c @@ -358,7 +358,7 @@ ctr_load(ctr_t *ctr) } -static void +static __inline void ctr_latch_status(ctr_t *ctr) { ctr->read_status = (ctr->ctrl & 0x3f) | (ctr->out ? 0x80 : 0) | (ctr->null_count ? 0x40 : 0); @@ -366,7 +366,7 @@ ctr_latch_status(ctr_t *ctr) } -static void +static __inline void ctr_latch_count(ctr_t *ctr) { int count = (ctr->latch || (ctr->state == 1)) ? ctr->l : ctr->count; @@ -459,8 +459,8 @@ pit_ctr_set_gate(ctr_t *ctr, int gate) } -void -pit_ctr_set_clock(ctr_t *ctr, int clock) +static __inline void +pit_ctr_set_clock_common(ctr_t *ctr, int clock) { int old = ctr->clock; @@ -491,6 +491,13 @@ pit_ctr_set_clock(ctr_t *ctr, int clock) } +void +pit_ctr_set_clock(ctr_t *ctr, int clock) +{ + pit_ctr_set_clock_common(ctr, clock); +} + + void pit_ctr_set_using_timer(ctr_t *ctr, int using_timer) { @@ -509,7 +516,7 @@ pit_timer_over(void *p) dev->clock ^= 1; for (i = 0; i < 3; i++) - pit_ctr_set_clock(&dev->counters[i], dev->clock); + pit_ctr_set_clock_common(&dev->counters[i], dev->clock); timer_advance_u64(&dev->callback_timer, PITCONST >> 1ULL); } diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index 0547c19c2..f8326b053 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -228,7 +228,7 @@ opl2_read(uint16_t port, void *priv) opl_t *dev = (opl_t *)priv; if (dev->flags & FLAG_CYCLES) - sub_cycles((int) (isa_timing * 8)); + cycles -= ((int) (isa_timing * 8)); opl2_update(dev); @@ -277,7 +277,7 @@ opl3_read(uint16_t port, void *priv) opl_t *dev = (opl_t *)priv; if (dev->flags & FLAG_CYCLES) - sub_cycles((int)(isa_timing * 8)); + cycles -= ((int)(isa_timing * 8)); opl3_update(dev); diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 1565bb8f2..353d25987 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1207,7 +1207,7 @@ sb_pro_v1_opl_read(uint16_t port, void *priv) { sb_t *sb = (sb_t *)priv; - sub_cycles((int)(isa_timing * 8)); + cycles -= ((int) (isa_timing * 8)); (void)opl2_read(port, &sb->opl2); // read, but ignore return(opl2_read(port, &sb->opl)); diff --git a/src/usb.c b/src/usb.c index fec6797ae..9692068b2 100644 --- a/src/usb.c +++ b/src/usb.c @@ -102,8 +102,10 @@ uhci_reg_writew(uint16_t addr, uint16_t val, void *p) switch (addr) { case 0x00: - if ((regs[0x00] & 0x0001) && !(val & 0x0001)) - regs[0x02] |= 0x20; + if ((val & 0x0001) && !(regs[0x00] & 0x0001)) + regs[0x01] &= ~0x20; + else if (!(val & 0x0001)) + regs[0x01] |= 0x20; regs[0x00] = (val & 0x00ff); break; case 0x06: diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index e7a5ffd61..60a662490 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -123,7 +123,7 @@ cga_waitstates(void *p) int ws; ws = ws_array[cycles & 0xf]; - sub_cycles(ws); + cycles -= ws; } diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index bb808e1dc..ca76ad23b 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -42,11 +42,7 @@ #define BIOS_GD5402_PATH L"roms/video/cirruslogic/avga2.rom" #define BIOS_GD5402_ONBOARD_PATH L"roms/machines/cbm_sl386sx25/Commodore386SX-25_AVGA2.bin" #define BIOS_GD5420_PATH L"roms/video/cirruslogic/5420.vbi" - -#if defined(DEV_BRANCH) && defined(USE_CL5422) #define BIOS_GD5422_PATH L"roms/video/cirruslogic/cl5422.bin" -#endif - #define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" #define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.bin" #define BIOS_GD5428_PATH L"roms/video/cirruslogic/vlbusjapan.BIN" @@ -535,6 +531,8 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga->adv_flags = FLAG_EXTRA_BANKS; if (svga->gdcreg[0xb] & 0x02) svga->adv_flags |= FLAG_ADDR_BY8; + if (svga->gdcreg[0xb] & 0x04) + svga->adv_flags |= FLAG_EXT_WRITE; if (svga->gdcreg[0xb] & 0x08) svga->adv_flags |= FLAG_LATCH8; gd54xx_recalc_banking(gd54xx); @@ -1447,6 +1445,7 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) case 4: if (svga->gdcreg[0xb] & 0x10) { addr <<= 2; + addr &= svga->decode_mask; for (i = 0; i < 8; i++) { if (val & svga->seqregs[2] & (0x80 >> i)) { @@ -1456,6 +1455,7 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) } } else { addr <<= 1; + addr &= svga->decode_mask; for (i = 0; i < 8; i++) { if (val & svga->seqregs[2] & (0x80 >> i)) @@ -1467,6 +1467,7 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) case 5: if (svga->gdcreg[0xb] & 0x10) { addr <<= 2; + addr &= svga->decode_mask; for (i = 0; i < 8; i++) { j = (0x80 >> i); @@ -1479,6 +1480,7 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) } } else { addr <<= 1; + addr &= svga->decode_mask; for (i = 0; i < 8; i++) { j = (0x80 >> i); @@ -1602,7 +1604,7 @@ gd54xx_readw_linear(uint32_t addr, void *p) temp |= (svga_readb_linear(addr, svga) << 8); if (svga->fast) - sub_cycles(video_timing_read_w); + cycles -= video_timing_read_w; return temp; case 3: @@ -1653,7 +1655,7 @@ gd54xx_readl_linear(uint32_t addr, void *p) temp |= (svga_readb_linear(addr + 2, svga) << 24); if (svga->fast) - sub_cycles(video_timing_read_l); + cycles -= video_timing_read_l; return temp; case 2: @@ -1663,7 +1665,7 @@ gd54xx_readl_linear(uint32_t addr, void *p) temp |= (svga_readb_linear(addr, svga) << 24); if (svga->fast) - sub_cycles(video_timing_read_l); + cycles -= video_timing_read_l; return temp; case 3: @@ -1852,7 +1854,7 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) svga_writeb_linear(addr, val >> 8, svga); if (svga->fast) - sub_cycles(video_timing_write_w); + cycles -= video_timing_write_w; case 3: return; } @@ -3072,12 +3074,10 @@ static void romfn = BIOS_GD5420_PATH; break; -#if defined(DEV_BRANCH) && defined(USE_CL5422) case CIRRUS_ID_CLGD5422: case CIRRUS_ID_CLGD5424: romfn = BIOS_GD5422_PATH; break; -#endif case CIRRUS_ID_CLGD5426: if (info->local & 0x200) @@ -3295,13 +3295,11 @@ gd5420_available(void) return rom_present(BIOS_GD5420_PATH); } -#if defined(DEV_BRANCH) && defined(USE_CL5422) static int gd5422_available(void) { return rom_present(BIOS_GD5422_PATH); } -#endif static int gd5426_available(void) @@ -3589,7 +3587,6 @@ const device_t gd5420_isa_device = gd5422_config, }; -#if defined(DEV_BRANCH) && defined(USE_CL5422) const device_t gd5422_isa_device = { "Cirrus Logic GD-5422", DEVICE_AT | DEVICE_ISA, @@ -3613,7 +3610,6 @@ const device_t gd5424_vlb_device = { gd54xx_force_redraw, gd5422_config, }; -#endif const device_t gd5426_vlb_device = { diff --git a/src/video/vid_colorplus.c b/src/video/vid_colorplus.c index 371d23e5e..223c4d1c6 100644 --- a/src/video/vid_colorplus.c +++ b/src/video/vid_colorplus.c @@ -100,7 +100,7 @@ void colorplus_write(uint32_t addr, uint8_t val, void *p) colorplus->cga.charbuffer[offset | 1] = colorplus->cga.vram[addr & 0x7fff]; } egawrites++; - sub_cycles(4); + cycles -= 4; } uint8_t colorplus_read(uint32_t addr, void *p) @@ -117,7 +117,7 @@ uint8_t colorplus_read(uint32_t addr, void *p) { addr &= 0x3FFF; } - sub_cycles(4); + cycles -= 4; if (colorplus->cga.snow_enabled) { int offset = ((timer_get_remaining_u64(&colorplus->cga.timer) / CGACONST) * 2) & 0xfc; diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index e47aed584..bbd8e7da9 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -732,7 +732,7 @@ ega_write(uint32_t addr, uint8_t val, void *p) int writemask2 = ega->writemask; egawrites++; - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; if (addr >= 0xB0000) addr &= 0x7fff; else addr &= 0xffff; @@ -859,7 +859,7 @@ ega_read(uint32_t addr, void *p) int readplane = ega->readplane; egareads++; - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; if (addr >= 0xb0000) addr &= 0x7fff; else addr &= 0xffff; diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index 6fbe02b94..d6afc1863 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -253,7 +253,7 @@ genius_waitstates(void) int ws; ws = ws_array[cycles & 0xf]; - sub_cycles(ws); + cycles -= ws; } diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 760774fe3..94faf3fea 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -212,7 +212,7 @@ hercules_waitstates(void *p) int ws; ws = ws_array[cycles & 0xf]; - sub_cycles(ws); + cycles -= ws; } diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index 79cfb6bdf..083de1f26 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -729,7 +729,7 @@ ht216_write_common(ht216_t *ht216, uint32_t addr, uint8_t val) svga_t *svga = &ht216->svga; uint8_t bit_mask = 0, rop_select = 0; - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; egawrites++; @@ -911,7 +911,7 @@ ht216_read_common(ht216_t *ht216, uint32_t addr) addr &= 0xfffff; - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; egareads++; diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 136531457..3433b7539 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -2132,7 +2132,7 @@ mystique_readb_linear(uint32_t addr, void *p) egareads++; - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2149,7 +2149,7 @@ mystique_readw_linear(uint32_t addr, void *p) egareads += 2; - sub_cycles(video_timing_read_w); + cycles -= video_timing_read_w; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2166,7 +2166,7 @@ mystique_readl_linear(uint32_t addr, void *p) egareads += 4; - sub_cycles(video_timing_read_l); + cycles -= video_timing_read_l; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2183,7 +2183,7 @@ mystique_writeb_linear(uint32_t addr, uint8_t val, void *p) egawrites++; - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2201,7 +2201,7 @@ mystique_writew_linear(uint32_t addr, uint16_t val, void *p) egawrites += 2; - sub_cycles(video_timing_write_w); + cycles -= video_timing_write_w; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -2219,7 +2219,7 @@ mystique_writel_linear(uint32_t addr, uint32_t val, void *p) egawrites += 4; - sub_cycles(video_timing_write_l); + cycles -= video_timing_write_l; addr &= svga->decode_mask; if (addr >= svga->vram_max) diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index e8862a68b..78812d27d 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -344,7 +344,7 @@ sigma_write(uint32_t addr, uint8_t val, void *p) sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)] = val; egawrites++; - sub_cycles(4); + cycles -= 4; } @@ -353,7 +353,7 @@ sigma_read(uint32_t addr, void *p) { sigma_t *sigma = (sigma_t *)p; - sub_cycles(4); + cycles -= 4; egareads++; return sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)]; } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 7a8fc0981..df81a9cb2 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1015,7 +1015,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) egawrites++; - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; if (!linear) { addr = svga_decode_addr(svga, addr, 1); @@ -1057,14 +1057,23 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) if (svga->adv_flags & FLAG_LATCH8) count = 8; + /* Undocumented Cirrus Logic behavior: The datasheet says that, with EXT_WRITE and FLAG_ADDR_BY8, the write mask only + changes meaning in write modes 4 and 5, as well as write mode 1. In reality, however, all other write modes are also + affected, as proven by the Windows 3.1 CL-GD 5422/4 drivers in 8bpp modes. */ switch (svga->writemode) { case 0: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; + val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); + // if (svga->gdcreg[3] & 7) + // val = svga_rotate[svga->gdcreg[3] & 7][val]; if ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = val; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = val; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = val; + } } return; } else { @@ -1078,8 +1087,13 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) break; case 1: for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = svga->latch.b[i]; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = svga->latch.b[i]; + } } return; case 2: @@ -1095,8 +1109,9 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) } break; case 3: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; + val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); + // if (svga->gdcreg[3] & 7) + // val = svga_rotate[svga->gdcreg[3] & 7][val]; wm = svga->gdcreg[8]; svga->gdcreg[8] &= val; @@ -1114,26 +1129,46 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) switch (svga->gdcreg[3] & 0x18) { case 0x00: /* Set */ for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } } break; case 0x08: /* AND */ for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] | ~svga->gdcreg[8]) & svga->latch.b[i]; + } } break; case 0x10: /* OR */ for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | svga->latch.b[i]; + } } break; case 0x18: /* XOR */ for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) ^ svga->latch.b[i]; + } } break; } @@ -1156,7 +1191,7 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) if (svga->adv_flags & FLAG_ADDR_BY8) readplane = svga->gdcreg[4] & 7; - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; egareads++; @@ -1182,6 +1217,9 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) addr = svga->translate_address(addr, p); if (addr >= svga->vram_max) return 0xff; + latch_addr = (addr & svga->vram_mask) & ~3; + for (i = 0; i < count; i++) + svga->latch.b[i] = svga->vram[latch_addr | i]; return svga->vram[addr & svga->vram_mask]; } else if (svga->chain2_read) { readplane = (readplane & 2) | (addr & 1); @@ -1381,7 +1419,7 @@ svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p) egawrites += 2; - sub_cycles(video_timing_write_w); + cycles -= video_timing_write_w; if (!linear) { addr = svga_decode_addr(svga, addr, 1); @@ -1442,7 +1480,7 @@ svga_writel_common(uint32_t addr, uint32_t val, uint8_t linear, void *p) egawrites += 4; - sub_cycles(video_timing_write_l); + cycles -= video_timing_write_l; if (!linear) { addr = svga_decode_addr(svga, addr, 1); @@ -1526,7 +1564,7 @@ svga_readw_common(uint32_t addr, uint8_t linear, void *p) egareads += 2; - sub_cycles(video_timing_read_w); + cycles -= video_timing_read_w; if (!linear) { addr = svga_decode_addr(svga, addr, 0); @@ -1579,7 +1617,7 @@ svga_readl_common(uint32_t addr, uint8_t linear, void *p) egareads += 4; - sub_cycles(video_timing_read_l); + cycles -= video_timing_read_l; if (!linear) { addr = svga_decode_addr(svga, addr, 0); diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 611be2524..e8605e16d 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -71,9 +71,7 @@ video_cards[] = { { "cl_gd5401_isa", &gd5401_isa_device }, { "cl_gd5402_isa", &gd5402_isa_device }, { "cl_gd5420_isa", &gd5420_isa_device }, -#if defined(DEV_BRANCH) && defined(USE_CL5422) { "cl_gd5422_isa", &gd5422_isa_device }, -#endif { "cl_gd5428_isa", &gd5428_isa_device }, { "cl_gd5429_isa", &gd5429_isa_device }, { "cl_gd5434_isa", &gd5434_isa_device }, @@ -154,9 +152,7 @@ video_cards[] = { { "voodoo3_3k_pci", &voodoo_3_3000_device }, { "mach64gx_vlb", &mach64gx_vlb_device }, { "et4000w32p_vlb", &et4000w32p_cardex_vlb_device }, -#if defined(DEV_BRANCH) && defined(USE_CL5422) { "cl_gd5424_vlb", &gd5424_vlb_device }, -#endif { "cl_gd5428_vlb", &gd5428_vlb_device }, { "cl_gd5429_vlb", &gd5429_vlb_device }, { "cl_gd5434_vlb", &gd5434_vlb_device }, diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index d5f28fefc..17415c10a 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -798,7 +798,7 @@ static uint8_t tgui_ext_linear_read(uint32_t addr, void *p) tgui_t *tgui = (tgui_t *)svga->p; int c; - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -829,7 +829,7 @@ static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; uint8_t mask = tgui->ext_gdc_regs[7]; - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -898,7 +898,7 @@ static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; uint16_t mask = (tgui->ext_gdc_regs[7] << 8) | tgui->ext_gdc_regs[8]; - sub_cycles(video_timing_write_w); + cycles -= video_timing_write_w; addr &= svga->decode_mask; if (addr >= svga->vram_max) diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index e8d2ad7d3..c806bf243 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -151,7 +151,7 @@ static uint16_t voodoo_readw(uint32_t addr, void *p) addr &= 0xffffff; - sub_cycles(voodoo->read_time); + cycles -= voodoo->read_time; if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ { @@ -190,7 +190,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) voodoo->rd_count++; addr &= 0xffffff; - sub_cycles(voodoo->read_time); + cycles -= voodoo->read_time; if (addr & 0x800000) /*Texture*/ { @@ -403,7 +403,7 @@ static void voodoo_writew(uint32_t addr, uint16_t val, void *p) voodoo->wr_count++; addr &= 0xffffff; - sub_cycles(voodoo->write_time); + cycles -= voodoo->write_time; if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ voodoo_queue_command(voodoo, addr | FIFO_WRITEW_FB, val); @@ -418,9 +418,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) addr &= 0xffffff; if (addr == voodoo->last_write_addr+4) - sub_cycles(voodoo->burst_time); + cycles -= voodoo->burst_time; else - sub_cycles(voodoo->write_time); + cycles -= voodoo->write_time; voodoo->last_write_addr = addr; if (addr & 0x800000) /*Texture*/ diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 932fb9ee6..0b664d91e 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -835,7 +835,7 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p) svga_t *svga = &banshee->svga; uint32_t ret = 0xffffffff; - sub_cycles(voodoo->read_time); + cycles -= voodoo->read_time; switch (addr & 0xff) { @@ -1026,7 +1026,7 @@ static uint32_t banshee_reg_readl(uint32_t addr, void *p) voodoo_t *voodoo = banshee->voodoo; uint32_t ret = 0xffffffff; - sub_cycles(voodoo->read_time); + cycles -= voodoo->read_time; switch (addr & 0x1f00000) { @@ -1178,7 +1178,7 @@ static void banshee_reg_writew(uint32_t addr, uint16_t val, void *p) banshee_t *banshee = (banshee_t *)p; voodoo_t *voodoo = banshee->voodoo; - sub_cycles(voodoo->write_time); + cycles -= voodoo->write_time; // banshee_log("banshee_reg_writew: addr=%08x val=%04x\n", addr, val); switch (addr & 0x1f00000) @@ -1253,9 +1253,9 @@ static void banshee_reg_writel(uint32_t addr, uint32_t val, void *p) voodoo_t *voodoo = banshee->voodoo; if (addr == voodoo->last_write_addr+4) - sub_cycles(voodoo->burst_time); + cycles -= voodoo->burst_time; else - sub_cycles(voodoo->write_time); + cycles -= voodoo->write_time; voodoo->last_write_addr = addr; // banshee_log("banshee_reg_writel: addr=%08x val=%08x\n", addr, val); @@ -1351,7 +1351,7 @@ static uint8_t banshee_read_linear(uint32_t addr, void *p) voodoo_t *voodoo = banshee->voodoo; svga_t *svga = &banshee->svga; - sub_cycles(voodoo->read_time); + cycles -= voodoo->read_time; addr &= svga->decode_mask; if (addr >= voodoo->tile_base) @@ -1369,7 +1369,7 @@ static uint8_t banshee_read_linear(uint32_t addr, void *p) return 0xff; egareads++; - sub_cycles(video_timing_read_b); + cycles -= video_timing_read_b; // banshee_log("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); @@ -1385,8 +1385,7 @@ static uint16_t banshee_read_linear_w(uint32_t addr, void *p) if (addr & 1) return banshee_read_linear(addr, p) | (banshee_read_linear(addr+1, p) << 8); - sub_cycles(voodoo->read_time); - + cycles -= voodoo->read_time; addr &= svga->decode_mask; if (addr >= voodoo->tile_base) { @@ -1403,7 +1402,7 @@ static uint16_t banshee_read_linear_w(uint32_t addr, void *p) return 0xff; egareads++; - sub_cycles(video_timing_read_w); + cycles -= video_timing_read_w; // banshee_log("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); @@ -1419,7 +1418,7 @@ static uint32_t banshee_read_linear_l(uint32_t addr, void *p) if (addr & 3) return banshee_read_linear_w(addr, p) | (banshee_read_linear_w(addr+2, p) << 16); - sub_cycles(voodoo->read_time); + cycles -= voodoo->read_time; addr &= svga->decode_mask; if (addr >= voodoo->tile_base) @@ -1437,7 +1436,7 @@ static uint32_t banshee_read_linear_l(uint32_t addr, void *p) return 0xff; egareads++; - sub_cycles(video_timing_read_l); + cycles -= video_timing_read_l; // banshee_log("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); @@ -1450,7 +1449,7 @@ static void banshee_write_linear(uint32_t addr, uint8_t val, void *p) voodoo_t *voodoo = banshee->voodoo; svga_t *svga = &banshee->svga; - sub_cycles(voodoo->write_time); + cycles -= voodoo->write_time; // banshee_log("write_linear: addr=%08x val=%02x\n", addr, val); addr &= svga->decode_mask; @@ -1470,7 +1469,7 @@ static void banshee_write_linear(uint32_t addr, uint8_t val, void *p) egawrites++; - sub_cycles(video_timing_write_b); + cycles -= video_timing_write_b; svga->changedvram[addr >> 12] = changeframecount; svga->vram[addr & svga->vram_mask] = val; @@ -1489,8 +1488,7 @@ static void banshee_write_linear_w(uint32_t addr, uint16_t val, void *p) return; } - sub_cycles(voodoo->write_time); - + cycles -= voodoo->write_time; // banshee_log("write_linear: addr=%08x val=%02x\n", addr, val); addr &= svga->decode_mask; if (addr >= voodoo->tile_base) @@ -1509,7 +1507,7 @@ static void banshee_write_linear_w(uint32_t addr, uint16_t val, void *p) egawrites++; - sub_cycles(video_timing_write_w); + cycles -= video_timing_write_w; svga->changedvram[addr >> 12] = changeframecount; *(uint16_t *)&svga->vram[addr & svga->vram_mask] = val; @@ -1533,7 +1531,7 @@ static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p) timing = voodoo->burst_time; else timing = voodoo->write_time; - sub_cycles(timing); + cycles -= timing; voodoo->last_write_addr = addr; // /*if (val) */banshee_log("write_linear_l: addr=%08x val=%08x %08x\n", addr, val, voodoo->tile_base); @@ -1555,7 +1553,7 @@ static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p) egawrites += 4; - sub_cycles(video_timing_write_l); + cycles -= video_timing_write_l; svga->changedvram[addr >> 12] = changeframecount; *(uint32_t *)&svga->vram[addr & svga->vram_mask] = val; diff --git a/src/video/video.c b/src/video/video.c index ce77e9abf..2b1a9bcd5 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -336,7 +336,7 @@ static png_infop info_ptr; static void -video_take_screenshot(const wchar_t *fn, int startx, int starty, int w, int h) +video_take_screenshot(const wchar_t *fn, int startx, int starty, int y1, int y2, int w, int h) { int i, x, y; png_bytep *b_rgb = NULL; @@ -382,7 +382,7 @@ video_take_screenshot(const wchar_t *fn, int startx, int starty, int w, int h) for (y = 0; y < h; ++y) { b_rgb[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); for (x = 0; x < w; ++x) { - temp = render_buffer->line[y + starty][x + startx]; + temp = render_buffer->dat[(y * w) + x]; b_rgb[y][(x) * 3 + 0] = (temp >> 16) & 0xff; b_rgb[y][(x) * 3 + 1] = (temp >> 8) & 0xff; @@ -407,7 +407,7 @@ video_take_screenshot(const wchar_t *fn, int startx, int starty, int w, int h) static void -video_screenshot(int x, int y, int w, int h) +video_screenshot(int x, int y, int y1, int y2, int w, int h) { wchar_t path[1024], fn[128]; @@ -426,7 +426,7 @@ video_screenshot(int x, int y, int w, int h) video_log("taking screenshot to: %S\n", path); - video_take_screenshot((const wchar_t *) path, x, y, w, h); + video_take_screenshot((const wchar_t *) path, x, y, y1, y2, w, h); png_destroy_write_struct(&png_ptr, &info_ptr); } @@ -449,20 +449,20 @@ video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) { int yy; - if ((w > 0) && (h > 0)) { - for (yy = 0; yy < h; yy++) { + if (y2 > 0) { + for (yy = y1; yy < y2; yy++) { if (((y + yy) >= 0) && ((y + yy) < buffer32->h)) { if (video_grayscale || invert_display) - video_transform_copy(&(render_buffer->line[y + yy][x]), &(buffer32->line[y + yy][x]), w); + video_transform_copy(&(render_buffer->dat)[yy * w], &(buffer32->line[y + yy][x]), w); else - memcpy(&(render_buffer->line[y + yy][x]), &(buffer32->line[y + yy][x]), w << 2); + memcpy(&(render_buffer->dat)[yy * w], &(buffer32->line[y + yy][x]), w << 2); } } } if (screenshots) { if (render_buffer != NULL) - video_screenshot(x, y, w, h); + video_screenshot(x, y, y1, y2, w, h); screenshots--; video_log("screenshot taken, %i left\n", screenshots); } diff --git a/src/vnc.c b/src/vnc.c index 5813767fb..09c00831f 100644 --- a/src/vnc.c +++ b/src/vnc.c @@ -176,7 +176,7 @@ vnc_blit(int x, int y, int y1, int y2, int w, int h) p = (uint32_t *)&(((uint32_t *)rfb->frameBuffer)[yy*VNC_MAX_X]); if ((y+yy) >= 0 && (y+yy) < VNC_MAX_Y) - memcpy(p, &(render_buffer->line[y+yy][x]), w*4); + memcpy(p, &(render_buffer->dat[yy * w]), w*4); } video_blit_complete(); diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 237e7f783..ae7f632e6 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -66,7 +66,8 @@ BEGIN POPUP "Re&nderer" BEGIN MENUITEM "&SDL (Software)", IDM_VID_SDL_SW - MENUITEM "&SDL (Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW + MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL #ifdef USE_VNC MENUITEM "&VNC", IDM_VID_VNC #endif diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index f35641d58..6fd9b04e8 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -509,10 +509,6 @@ ifeq ($(AMD_K5), y) OPTS += -DUSE_AMD_K5 endif -ifeq ($(CL5422), y) -OPTS += -DUSE_CL5422 -endif - ifeq ($(CYRIX_6X86), y) OPTS += -DUSE_CYRIX_6X86 endif diff --git a/src/win/win.c b/src/win/win.c index 541a05d1a..0d465f2f3 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -89,14 +89,16 @@ static const struct { } vid_apis[2][RENDERERS_NUM] = { { { "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable }, - { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable } + { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable }, + { "SDL_OpenGL", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable } #ifdef USE_VNC ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL } #endif }, { { "SDL_Software", 1, (int(*)(void*))sdl_inits_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable }, - { "SDL_Hardware", 1, (int(*)(void*))sdl_inith_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable } + { "SDL_Hardware", 1, (int(*)(void*))sdl_inith_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable }, + { "SDL_OpenGL", 1, (int(*)(void*))sdl_initho_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable } #ifdef USE_VNC ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL } #endif @@ -700,9 +702,12 @@ plat_vidapi_name(int api) break; case 1: break; + case 2: + name = "sdl_opengl"; + break; #ifdef USE_VNC - case 2: + case 3: name = "vnc"; break; #endif @@ -762,12 +767,21 @@ plat_vidsize(int x, int y) void plat_vidapi_enable(int enable) { + int i = 1; + if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].enable) return; startblit(); video_wait_for_blit(); - vid_apis[video_fullscreen][vid_api].enable(enable); + + vid_apis[video_fullscreen][vid_api].enable(enable & 1); + endblit(); + + if (! i) return; + + if (enable) + device_force_redraw(); } int diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index 9d3a9b4cd..db12f2cc8 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -75,6 +75,7 @@ #define RENDERER_FULL_SCREEN 1 #define RENDERER_HARDWARE 2 +#define RENDERER_OPENGL 4 static SDL_Window *sdl_win = NULL; @@ -83,12 +84,55 @@ static SDL_Texture *sdl_tex = NULL; static HWND sdl_parent_hwnd = NULL; static HWND sdl_hwnd = NULL; static int sdl_w, sdl_h; -static int sdl_fs; +static int sdl_fs, sdl_flags = -1; static int cur_w, cur_h; +static int cur_wx = 0, cur_wy = 0, cur_ww =0, cur_wh = 0; static volatile int sdl_enabled = 0; static SDL_mutex* sdl_mutex = NULL; +typedef struct +{ + const void *magic; + Uint32 id; + char *title; + SDL_Surface *icon; + int x, y; + int w, h; + int min_w, min_h; + int max_w, max_h; + Uint32 flags; + Uint32 last_fullscreen_flags; + + /* Stored position and size for windowed mode */ + SDL_Rect windowed; + + SDL_DisplayMode fullscreen_mode; + + float brightness; + Uint16 *gamma; + Uint16 *saved_gamma; /* (just offset into gamma) */ + + SDL_Surface *surface; + SDL_bool surface_valid; + + SDL_bool is_hiding; + SDL_bool is_destroying; + + void *shaper; + + SDL_HitTest hit_test; + void *hit_test_data; + + void *data; + + void *driverdata; + + SDL_Window *prev; + SDL_Window *next; +} SDL_Window_Ex; + + #ifdef ENABLE_SDL_LOG int sdl_do_log = ENABLE_SDL_LOG; @@ -190,9 +234,7 @@ static void sdl_blit(int x, int y, int y1, int y2, int w, int h) { SDL_Rect r_src; - void *pixeldata; - int pitch; - int yy, ret; + int ret; if (!sdl_enabled) { video_blit_complete(); @@ -211,22 +253,13 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) SDL_LockMutex(sdl_mutex); - /* - * TODO: - * SDL_UpdateTexture() might be better here, as it is - * (reportedly) slightly faster. - */ - SDL_LockTexture(sdl_tex, 0, &pixeldata, &pitch); - - for (yy = y1; yy < y2; yy++) { - if ((y + yy) >= 0 && (y + yy) < render_buffer->h) - memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(render_buffer->line[y + yy][x]), w * 4); - } - + r_src.x = 0; + r_src.y = y1; + r_src.w = w; + r_src.h = y2 - y1; + SDL_UpdateTexture(sdl_tex, &r_src, &(render_buffer->dat)[y1 * w], w * 4); video_blit_complete(); - SDL_UnlockTexture(sdl_tex); - if (sdl_fs) { sdl_log("sdl_blit(%i, %i, %i, %i, %i, %i) (%i, %i)\n", x, y, y1, y2, w, h, unscaled_size_x, efscrnsz_y); if (w == unscaled_size_x) @@ -234,6 +267,8 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) sdl_log("(%08X, %08X, %08X)\n", sdl_win, sdl_render, sdl_tex); } + SDL_RenderClear(sdl_render); + r_src.x = 0; r_src.y = 0; r_src.w = w; @@ -252,6 +287,8 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) void sdl_close(void) { + SDL_LockMutex(sdl_mutex); + /* Unregister our renderer! */ video_setblit(NULL); @@ -297,6 +334,8 @@ sdl_close(void) /* Quit. */ SDL_Quit(); + + sdl_flags = -1; } @@ -340,8 +379,12 @@ sdl_init_common(int flags) return(0); } - if (flags & RENDERER_HARDWARE) - sdl_select_best_hw_driver(); + if (flags & RENDERER_HARDWARE) { + if (flags & RENDERER_OPENGL) + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "OpenGL"); + else + sdl_select_best_hw_driver(); + } if (flags & RENDERER_FULL_SCREEN) { /* Get the size of the (current) desktop. */ @@ -461,6 +504,8 @@ sdl_init_common(int flags) sdl_mutex = SDL_CreateMutex(); + sdl_flags = flags; + return(1); } @@ -479,6 +524,13 @@ sdl_inith(HWND h) } +int +sdl_initho(HWND h) +{ + return sdl_init_common(RENDERER_HARDWARE | RENDERER_OPENGL); +} + + int sdl_inits_fs(HWND h) { @@ -493,15 +545,30 @@ sdl_inith_fs(HWND h) } +int +sdl_initho_fs(HWND h) +{ + return sdl_init_common(RENDERER_FULL_SCREEN | RENDERER_HARDWARE | RENDERER_OPENGL); +} + + void sdl_reinit_texture() { - if (sdl_render == NULL) + if ((sdl_render == NULL) || (sdl_flags == -1)) return; SDL_DestroyTexture(sdl_tex); + SDL_DestroyRenderer(sdl_render); + if (sdl_flags & RENDERER_HARDWARE) { + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); + } else + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 2048, 2048); + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + SDL_SetWindowPosition(sdl_win, cur_wx, cur_wy); } @@ -520,6 +587,8 @@ sdl_resize(int x, int y) if ((x == cur_w) && (y == cur_h)) return; + SDL_LockMutex(sdl_mutex); + ww = x; wh = y; @@ -531,12 +600,26 @@ sdl_resize(int x, int y) cur_w = x; cur_h = y; + cur_wx = wx; + cur_wy = wy; + cur_ww = ww; + cur_wh = wh; + sdl_reinit_texture(); + + SDL_UnlockMutex(sdl_mutex); } void sdl_enable(int enable) { + if (sdl_flags == -1) + return; + + SDL_LockMutex(sdl_mutex); sdl_enabled = enable; + if (enable) + sdl_reinit_texture(); + SDL_UnlockMutex(sdl_mutex); } diff --git a/src/win/win_settings.c b/src/win/win_settings.c index c18006d9a..ea102e36b 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -2232,10 +2232,18 @@ win_settings_hard_disks_resize_columns(HWND hdlg) { /* Bus, File, Cylinders, Heads, Sectors, Size */ int iCol, width[C_COLUMNS_HARD_DISKS] = {104, 177, 50, 26, 32, 50}; + int total = 0; HWND hwndList = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + RECT r; - for (iCol = 0; iCol < C_COLUMNS_HARD_DISKS; iCol++) + GetWindowRect(hwndList, &r); + for (iCol = 0; iCol < (C_COLUMNS_HARD_DISKS - 1); iCol++) { + width[iCol] = MulDiv(width[iCol], dpi, 96); + total += width[iCol]; ListView_SetColumnWidth(hwndList, iCol, MulDiv(width[iCol], dpi, 96)); + } + width[C_COLUMNS_HARD_DISKS - 1] = (r.right - r.left) - 4 - total; + ListView_SetColumnWidth(hwndList, C_COLUMNS_HARD_DISKS - 1, width[C_COLUMNS_HARD_DISKS - 1]); } @@ -3678,11 +3686,19 @@ win_settings_zip_drives_recalc_list(HWND hdlg) static void win_settings_floppy_drives_resize_columns(HWND hdlg) { + int iCol, width[3] = {292, 58, 89}; + int total = 0; HWND hwndList = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + RECT r; - ListView_SetColumnWidth(hwndList, 0, MulDiv(292, dpi, 96)); - ListView_SetColumnWidth(hwndList, 1, MulDiv(58, dpi, 96)); - ListView_SetColumnWidth(hwndList, 2, MulDiv(89, dpi, 96)); + GetWindowRect(hwndList, &r); + for (iCol = 0; iCol < 2; iCol++) { + width[iCol] = MulDiv(width[iCol], dpi, 96); + total += width[iCol]; + ListView_SetColumnWidth(hwndList, iCol, MulDiv(width[iCol], dpi, 96)); + } + width[2] = (r.right - r.left) - 4 - total; + ListView_SetColumnWidth(hwndList, 2, width[2]); } @@ -3729,10 +3745,15 @@ win_settings_floppy_drives_init_columns(HWND hdlg) static void win_settings_cdrom_drives_resize_columns(HWND hdlg) { + int width[2] = {292, 147}; HWND hwndList = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + RECT r; - ListView_SetColumnWidth(hwndList, 0, MulDiv(292, dpi, 96)); - ListView_SetColumnWidth(hwndList, 1, MulDiv(147, dpi, 96)); + GetWindowRect(hwndList, &r); + width[0] = MulDiv(width[0], dpi, 96); + ListView_SetColumnWidth(hwndList, 0, MulDiv(width[0], dpi, 96)); + width[1] = (r.right - r.left) - 4 - width[0]; + ListView_SetColumnWidth(hwndList, 1, width[1]); } @@ -3770,10 +3791,15 @@ win_settings_cdrom_drives_init_columns(HWND hdlg) static void win_settings_mo_drives_resize_columns(HWND hdlg) { + int width[2] = {292, 147}; HWND hwndList = GetDlgItem(hdlg, IDC_LIST_MO_DRIVES); + RECT r; - ListView_SetColumnWidth(hwndList, 0, MulDiv(292, dpi, 96)); - ListView_SetColumnWidth(hwndList, 1, MulDiv(147, dpi, 96)); + GetWindowRect(hwndList, &r); + width[0] = MulDiv(width[0], dpi, 96); + ListView_SetColumnWidth(hwndList, 0, MulDiv(width[0], dpi, 96)); + width[1] = (r.right - r.left) - 4 - width[0]; + ListView_SetColumnWidth(hwndList, 1, width[1]); } @@ -3811,10 +3837,15 @@ win_settings_mo_drives_init_columns(HWND hdlg) static void win_settings_zip_drives_resize_columns(HWND hdlg) { + int width[2] = {292, 147}; HWND hwndList = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + RECT r; - ListView_SetColumnWidth(hwndList, 0, MulDiv(292, dpi, 96)); - ListView_SetColumnWidth(hwndList, 1, MulDiv(147, dpi, 96)); + GetWindowRect(hwndList, &r); + width[0] = MulDiv(width[0], dpi, 96); + ListView_SetColumnWidth(hwndList, 0, MulDiv(width[0], dpi, 96)); + width[1] = (r.right - r.left) - 4 - width[0]; + ListView_SetColumnWidth(hwndList, 1, width[1]); } @@ -4981,6 +5012,17 @@ win_settings_confirm(HWND hdlg) } +static void +win_settings_categories_resize_columns(HWND hdlg) +{ + HWND hwndList = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + RECT r; + + GetWindowRect(hwndList, &r); + ListView_SetColumnWidth(hwndList, 0, (r.right - r.left) + 1 - 5); +} + + static BOOL win_settings_categories_init_columns(HWND hdlg) { @@ -4999,20 +5041,11 @@ win_settings_categories_init_columns(HWND hdlg) if (ListView_InsertColumn(hwndList, iCol, &lvc) == -1) return FALSE; - win_settings_hard_disks_resize_columns(hdlg); + win_settings_categories_resize_columns(hdlg); return TRUE; } -static void -win_settings_categories_resize_columns(HWND hdlg) -{ - HWND hwndList = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); - - ListView_SetColumnWidth(hwndList, 0, MulDiv(171, dpi, 96)); -} - - #if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 51dbb9e46..5dd4026c5 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -216,6 +216,7 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_RESIZE, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SDL_SW, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SDL_HW, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SDL_OPENGL, MF_UNCHECKED); #ifdef USE_VNC CheckMenuItem(menuMain, IDM_VID_VNC, MF_UNCHECKED); #endif @@ -418,7 +419,6 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case IDM_ACTION_RESET_CAD: - pclog("-\n"); pc_send_cad(); break; @@ -538,6 +538,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_VID_SDL_SW: case IDM_VID_SDL_HW: + case IDM_VID_SDL_OPENGL: #ifdef USE_VNC case IDM_VID_VNC: #endif @@ -730,6 +731,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) temp_y = (lParam >> 16); if ((temp_x <= 0) || (temp_y <= 0)) { + plat_vidapi_enable(0); minimized = 1; break; } else if (minimized == 1) { @@ -936,6 +938,14 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) #endif break; + case WM_ACTIVATE: + if (wParam != WA_INACTIVE) { + video_force_resize_set(1); + plat_vidapi_enable(0); + plat_vidapi_enable(1); + } + break; + case WM_ENTERSIZEMOVE: user_resize = 1; break; @@ -1071,18 +1081,18 @@ ui_init(int nCmdShow) ui_window_title(title); - /* Get the current DPI */ - dpi = win_get_dpi(hwndMain); + /* Get the current DPI */ + dpi = win_get_dpi(hwndMain); - /* Check if we have a padded window frame */ - padded_frame = (GetSystemMetrics(SM_CXPADDEDBORDER) != 0); + /* Check if we have a padded window frame */ + padded_frame = (GetSystemMetrics(SM_CXPADDEDBORDER) != 0); /* Create the status bar window. */ StatusBarCreate(hwndMain, IDC_STATUS, hinstance); - /* Get the actual height of the status bar */ - GetWindowRect(hwndSBAR, &sbar_rect); - sbar_height = sbar_rect.bottom - sbar_rect.top; + /* Get the actual height of the status bar */ + GetWindowRect(hwndSBAR, &sbar_rect); + sbar_height = sbar_rect.bottom - sbar_rect.top; /* Set up main window for resizing if configured. */ if (vid_resize) From 4ea181ba54d8f0b800cf0e08d7b940a4c98a68a1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 26 Nov 2020 18:22:18 +0100 Subject: [PATCH 46/67] Ported the recent Voodoo Banshee/3 commit from PCem. --- src/video/vid_voodoo_banshee.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 0b664d91e..2be43715c 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -1157,7 +1157,7 @@ static uint32_t banshee_reg_readl(uint32_t addr, void *p) break; default: - fatal("banshee_reg_readl: 3D addr=%08x\n", addr); + banshee_log("banshee_reg_readl: 3D addr=%08x\n", addr); break; } break; From 01b413110abc263678d5e36c5788d2cf267b1072 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 26 Nov 2020 18:59:25 +0100 Subject: [PATCH 47/67] The Settings dialog now once again omits the "Internal" option for hard disk controller for machines without one. --- src/include/86box/machine.h | 2 +- src/win/win_settings.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 9cb155f81..055ed5363 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -65,7 +65,7 @@ /* Combined flags. */ #define MACHINE_VIDEO_FIXED 0x00003000 /* sys has fixed int video */ /* Feature flags for internal storage controllers. */ -#define MACHINE_HDC 0x0FFC0000 /* sys has int HDC */ +#define MACHINE_HDC 0x07FC0000 /* sys has int HDC */ #define MACHINE_MFM 0x00100000 /* sys has int MFM/RLL */ #define MACHINE_XTA 0x00200000 /* sys has int XTA */ #define MACHINE_ESDI 0x00400000 /* sys has int ESDI */ diff --git a/src/win/win_settings.c b/src/win/win_settings.c index ea102e36b..a898001f0 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -1523,6 +1523,12 @@ win_settings_storage_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) c = d = 0; settings_reset_content(hdlg, IDC_COMBO_HDC); while (1) { + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && !(machines[temp_machine].flags & MACHINE_HDC)) { + c++; + continue; + } + generate_device_name(hdc_get_device(c), hdc_get_internal_name(c), 1); if (!device_name[0]) From 55ed92f801382c69146724b9087f9ba263f53417 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 26 Nov 2020 19:01:48 +0100 Subject: [PATCH 48/67] Added the Cirrus change to the forgotten Write mode 2. --- src/video/vid_svga.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index df81a9cb2..efe663d8c 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1102,8 +1102,13 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { for (i = 0; i < count; i++) { - if (writemask2 & (1 << i)) - svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { + if (writemask2 & (0x80 >> i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } else { + if (writemask2 & (1 << i)) + svga->vram[addr | i] = (vall.b[i] & svga->gdcreg[8]) | (svga->latch.b[i] & ~svga->gdcreg[8]); + } } return; } From 8671351c84aaa8f38e2634dd3c3ead7f8d6f0cee Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 26 Nov 2020 22:32:43 +0100 Subject: [PATCH 49/67] Ported the latest bunch of Voodoo related commits from PCem. --- src/include/86box/vid_voodoo_common.h | 5 ++ src/video/vid_voodoo_banshee_blitter.c | 93 ++++++++++++++++++++++---- 2 files changed, 85 insertions(+), 13 deletions(-) diff --git a/src/include/86box/vid_voodoo_common.h b/src/include/86box/vid_voodoo_common.h index fe2f0b32c..85b97c7d2 100644 --- a/src/include/86box/vid_voodoo_common.h +++ b/src/include/86box/vid_voodoo_common.h @@ -385,6 +385,8 @@ typedef struct voodoo_t uint32_t dstFormat; uint32_t dstSize; uint32_t dstXY; + uint32_t lineStipple; + uint32_t lineStyle; uint32_t rop; uint32_t srcBaseAddr; uint32_t srcFormat; @@ -432,6 +434,9 @@ typedef struct voodoo_t int src_stride_src, src_stride_dest; int src_bpp; + + int line_pix_pos, line_bit_pos; + int line_rep_cnt, line_bit_mask_size; } banshee_blt; struct diff --git a/src/video/vid_voodoo_banshee_blitter.c b/src/video/vid_voodoo_banshee_blitter.c index 2e5beef91..5ecabcdaa 100644 --- a/src/video/vid_voodoo_banshee_blitter.c +++ b/src/video/vid_voodoo_banshee_blitter.c @@ -43,6 +43,7 @@ #define COMMAND_INITIATE (1 << 8) #define COMMAND_INC_X_START (1 << 10) #define COMMAND_INC_Y_START (1 << 11) +#define COMMAND_STIPPLE_LINE (1 << 12) #define COMMAND_PATTERN_MONO (1 << 13) #define COMMAND_DX (1 << 14) #define COMMAND_DY (1 << 15) @@ -246,6 +247,50 @@ static void PLOT(voodoo_t *voodoo, int x, int y, int pat_x, int pat_y, uint8_t p } } +static void PLOT_LINE(voodoo_t *voodoo, int x, int y, uint8_t rop, uint32_t pattern, int src_colorkey) +{ + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t addr = get_addr(voodoo, x, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = voodoo->vram[addr]; + + voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_8); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t addr = get_addr(voodoo, x*2, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*2 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint16_t *)&voodoo->vram[addr]; + + *(uint16_t *)&voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_16); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t addr = get_addr(voodoo, x*3, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*3 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + + *(uint32_t *)&voodoo->vram[addr] = (MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t addr = get_addr(voodoo, x*4, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*4 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + + *(uint32_t *)&voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + } +} + + static void update_src_stride(voodoo_t *voodoo) { int bpp; @@ -858,14 +903,24 @@ static void banshee_do_host_to_screen_stretch_blt(voodoo_t *voodoo, int count, u } } +static void step_line(voodoo_t *voodoo) +{ + if (voodoo->banshee_blt.line_pix_pos == voodoo->banshee_blt.line_rep_cnt) + { + voodoo->banshee_blt.line_pix_pos = 0; + if (voodoo->banshee_blt.line_bit_pos == voodoo->banshee_blt.line_bit_mask_size) + voodoo->banshee_blt.line_bit_pos = 0; + else + voodoo->banshee_blt.line_bit_pos++; + } + else + voodoo->banshee_blt.line_pix_pos++; +} + + static void banshee_do_line(voodoo_t *voodoo) { clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; - uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; - int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.srcY); - int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.srcX; - int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == - (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); uint8_t rop = voodoo->banshee_blt.command >> 24; int dx = ABS(voodoo->banshee_blt.dstX - voodoo->banshee_blt.srcX); int dy = ABS(voodoo->banshee_blt.dstY - voodoo->banshee_blt.srcY); @@ -874,17 +929,19 @@ static void banshee_do_line(voodoo_t *voodoo) int x = voodoo->banshee_blt.srcX; int y = voodoo->banshee_blt.srcY; int error; + uint32_t stipple = (voodoo->banshee_blt.command & COMMAND_STIPPLE_LINE) ? + voodoo->banshee_blt.lineStipple : ~0; if (dx > dy) /*X major*/ { error = dx/2; while (x != voodoo->banshee_blt.dstX) { - uint8_t pattern_mask = pattern_mono[pat_y & 7]; - int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); + int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) - PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); error -= dy; if (error < 0) @@ -894,7 +951,7 @@ static void banshee_do_line(voodoo_t *voodoo) pat_y += y_inc; } x += x_inc; - pat_x += x_inc; + step_line(voodoo); } } else /*Y major*/ @@ -902,11 +959,11 @@ static void banshee_do_line(voodoo_t *voodoo) error = dy/2; while (y != voodoo->banshee_blt.dstY) { - uint8_t pattern_mask = pattern_mono[pat_y & 7]; - int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); + int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) - PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); error -= dx; if (error < 0) @@ -916,7 +973,7 @@ static void banshee_do_line(voodoo_t *voodoo) pat_x += x_inc; } y += y_inc; - pat_y += y_inc; + step_line(voodoo); } } @@ -1141,6 +1198,16 @@ void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) case 0x38: voodoo->banshee_blt.commandExtra = val; // bansheeblt_log("commandExtra=%08x\n", val); + break; + case 0x3c: + voodoo->banshee_blt.lineStipple = val; + break; + case 0x40: + voodoo->banshee_blt.lineStyle = val; + voodoo->banshee_blt.line_rep_cnt = val & 0xff; + voodoo->banshee_blt.line_bit_mask_size = (val >> 8) & 0x1f; + voodoo->banshee_blt.line_pix_pos = (val >> 16) & 0xff; + voodoo->banshee_blt.line_bit_pos = (val >> 24) & 0x1f; break; case 0x44: voodoo->banshee_blt.colorPattern[0] = val; From 8a6a79d54a8284c174793b73c7a0bcd0cbf8228d Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 26 Nov 2020 22:57:37 +0100 Subject: [PATCH 50/67] Fixed a mistake while porting. --- src/video/vid_voodoo_banshee_blitter.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/video/vid_voodoo_banshee_blitter.c b/src/video/vid_voodoo_banshee_blitter.c index 5ecabcdaa..d86ff8eb9 100644 --- a/src/video/vid_voodoo_banshee_blitter.c +++ b/src/video/vid_voodoo_banshee_blitter.c @@ -948,7 +948,6 @@ static void banshee_do_line(voodoo_t *voodoo) { error += dx; y += y_inc; - pat_y += y_inc; } x += x_inc; step_line(voodoo); @@ -970,7 +969,6 @@ static void banshee_do_line(voodoo_t *voodoo) { error += dy; x += x_inc; - pat_x += x_inc; } y += y_inc; step_line(voodoo); From 7c78fa467279162d7df54aed319a2c3efd940b70 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 26 Nov 2020 22:58:53 +0100 Subject: [PATCH 51/67] Fixed two compile-breaking mistakes in the Voodoo Banshee/3 Blitter. --- src/video/vid_voodoo_banshee_blitter.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/video/vid_voodoo_banshee_blitter.c b/src/video/vid_voodoo_banshee_blitter.c index 5ecabcdaa..d86ff8eb9 100644 --- a/src/video/vid_voodoo_banshee_blitter.c +++ b/src/video/vid_voodoo_banshee_blitter.c @@ -948,7 +948,6 @@ static void banshee_do_line(voodoo_t *voodoo) { error += dx; y += y_inc; - pat_y += y_inc; } x += x_inc; step_line(voodoo); @@ -970,7 +969,6 @@ static void banshee_do_line(voodoo_t *voodoo) { error += dy; x += x_inc; - pat_x += x_inc; } y += y_inc; step_line(voodoo); From 1df797dfda3e2f64b5a8215ae6a1682780be9eea Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 27 Nov 2020 02:59:56 +0100 Subject: [PATCH 52/67] Fixed word pushes onto the stack in cpu/x86seg.c, fixes Windows 3.0 on 386SX, closes #1128. --- src/cpu/x86seg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index b15e4bd46..64ea5dd6f 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -808,8 +808,8 @@ void PUSHL(uint32_t v) { if (cpu_16bitbus) { - PUSHW(v & 0xffff); PUSHW(v >> 16); + PUSHW(v & 0xffff); } else { if (stack32) { writememl(ss, ESP - 4, v); From f9c2f04a52a52db5c009acfde133d5a8a30dc0ef Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 28 Nov 2020 07:02:38 +0100 Subject: [PATCH 53/67] 808x fixes - 8088mph works normally again. --- src/cpu/808x.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 4932b9494..72a66703f 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -279,7 +279,7 @@ resub_cycles(int old_cycles) if (old_cycles > cycles) { cyc_diff = old_cycles - cycles; cycles = old_cycles; - resub_cycles(cyc_diff); + sub_cycles(cyc_diff); } } @@ -298,27 +298,35 @@ cpu_io(int bits, int out, uint16_t port) if (out) { wait(4, 1); if (bits == 16) { - if (is8086 && !(port & 1)) + if (is8086 && !(port & 1)) { + old_cycles = cycles; outw(port, AX); - else { + } else { wait(4, 1); + old_cycles = cycles; outb(port++, AL); outb(port, AH); } - } else + } else { + old_cycles = cycles; outb(port, AL); + } } else { wait(4, 1); if (bits == 16) { - if (is8086 && !(port & 1)) + if (is8086 && !(port & 1)) { + old_cycles = cycles; AX = inw(port); - else { + } else { wait(4, 1); + old_cycles = cycles; AL = inb(port++); AH = inb(port); } - } else + } else { + old_cycles = cycles; AL = inb(port); + } } resub_cycles(old_cycles); From 546c2788f02bbedf320a0f70ccf1c218e5736916 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 28 Nov 2020 07:03:26 +0100 Subject: [PATCH 54/67] Fixed the Cirrus Logic CL-GD 5480 on NT 5.x and ported tonioni's Cirrus improvements from WinUAE where relevant. --- src/video/vid_cl54xx.c | 776 ++++++++++++++++++++++++++++++++++++++--- src/video/vid_svga.c | 4 - 2 files changed, 731 insertions(+), 49 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index ca76ad23b..96a4e13a1 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -11,11 +11,13 @@ * * * - * Authors: TheCollector1995, - * Miran Grca, + * Authors: Miran Grca, + * tonioni, + * TheCollector1995, * - * Copyright 2016-2020 TheCollector1995. * Copyright 2016-2020 Miran Grca. + * Copyright 2020 tonioni. + * Copyright 2016-2020 TheCollector1995. */ #include #include @@ -89,7 +91,7 @@ #define CIRRUS_CURSOR_HIDDENPEL 0x02 #define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, 32x32 if clear */ -// sequencer 0x17 +/* sequencer 0x17 */ #define CIRRUS_BUSTYPE_VLBFAST 0x10 #define CIRRUS_BUSTYPE_PCI 0x20 #define CIRRUS_BUSTYPE_VLBSLOW 0x30 @@ -98,7 +100,7 @@ #define CIRRUS_MMIO_USE_PCIADDR 0x40 /* 0xb8000 if cleared. */ #define CIRRUS_MEMSIZEEXT_DOUBLE 0x80 -// control 0x0b +/* control 0x0b */ #define CIRRUS_BANKING_DUAL 0x01 #define CIRRUS_BANKING_GRANULARITY_16K 0x20 /* set:16k, clear:4k */ @@ -115,7 +117,7 @@ #define CIRRUS_BLTMODE_PIXELWIDTH24 0x20 #define CIRRUS_BLTMODE_PIXELWIDTH32 0x30 -// control 0x31 +/* control 0x31 */ #define CIRRUS_BLT_BUSY 0x01 #define CIRRUS_BLT_START 0x02 #define CIRRUS_BLT_RESET 0x04 @@ -124,7 +126,7 @@ #define CIRRUS_BLT_APERTURE2 0x40 #define CIRRUS_BLT_AUTOSTART 0x80 -// control 0x33 +/* control 0x33 */ #define CIRRUS_BLTMODEEXT_BACKGROUNDONLY 0x08 #define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 #define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02 @@ -146,6 +148,7 @@ typedef struct gd54xx_t mem_mapping_t mmio_mapping; mem_mapping_t linear_mapping; mem_mapping_t aperture2_mapping; + mem_mapping_t vgablt_mapping; svga_t svga; @@ -187,11 +190,24 @@ typedef struct gd54xx_t int unlock_special; } blt; - int pci, vlb, mca; - int countminusone; + struct { + int mode; + uint16_t stride, r1sz, r1adjust, r2sz, + r2adjust, r2sdz, wvs, wve, + hzoom, vzoom; + uint8_t occlusion, colorkeycomparemask, + colorkeycompare; + int region1size, region2size, + colorkeymode; + uint32_t ck; + } overlay; + + int pci, vlb, mca, countminusone; + int vblank_irq, vportsync; uint8_t pci_regs[256]; - uint8_t int_line, unlocked; + uint8_t int_line, unlocked, status, extensions; + uint8_t crtcreg_mask; uint8_t fc; /* Feature Connector */ @@ -200,7 +216,7 @@ typedef struct gd54xx_t uint8_t pos_regs[8]; svga_t *mb_vga; - uint32_t lfb_base; + uint32_t lfb_base, vgablt_base; int mmio_vram_overlap; @@ -243,6 +259,266 @@ static void gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *svga); +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define DECODE_YCbCr() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +/*Both YUV formats are untested*/ +#define DECODE_YUV211() \ + do \ + { \ + uint8_t y1, y2, y3, y4; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + y2 = (298 * (src[2] - 16)) >> 8; \ + V = src[3] - 0x80; \ + y3 = (298 * (src[4] - 16)) >> 8; \ + y4 = (298 * (src[5] - 16)) >> 8; \ + src += 6; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + r[x_write+2] = y3 + dR; \ + CLAMP(r[x_write+2]); \ + g[x_write+2] = y3 - dG; \ + CLAMP(g[x_write+2]); \ + b[x_write+2] = y3 + dB; \ + CLAMP(b[x_write+2]); \ + \ + r[x_write+3] = y4 + dR; \ + CLAMP(r[x_write+3]); \ + g[x_write+3] = y4 - dG; \ + CLAMP(g[x_write+3]); \ + b[x_write+3] = y4 + dB; \ + CLAMP(b[x_write+3]); \ + \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_YUV422() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + V = src[2] - 0x80; \ + y2 = (298 * (src[3] - 16)) >> 8; \ + src += 4; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +#define DECODE_RGB555() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \ + b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \ + b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_CLUT() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint8_t dat; \ + \ + dat = *(uint8_t *)src; \ + src++; \ + \ + r[x_write + c] = svga->pallook[dat] >> 0; \ + g[x_write + c] = svga->pallook[dat] >> 8; \ + b[x_write + c] = svga->pallook[dat] >> 16; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + + + +#define OVERLAY_SAMPLE() \ + do \ + { \ + switch (gd54xx->overlay.mode) \ + { \ + case 0: \ + DECODE_YUV422(); \ + break; \ + case 2: \ + DECODE_CLUT(); \ + break; \ + case 3: \ + DECODE_YUV211(); \ + break; \ + case 4: \ + DECODE_RGB555(); \ + break; \ + case 5: \ + DECODE_RGB565(); \ + break; \ + } \ + } while (0) + + +static int +gd54xx_interrupt_enabled(gd54xx_t *gd54xx) +{ + return !gd54xx->pci || (gd54xx->svga.gdcreg[0x17] & 0x04); +} + + +static int +gd54xx_vga_vsync_enabled(gd54xx_t *gd54xx) +{ + if (!(gd54xx->svga.crtc[0x11] & 0x20) && (gd54xx->svga.crtc[0x11] & 0x10) && + gd54xx_interrupt_enabled(gd54xx)) + return 1; + return 0; +} + + +static void +gd54xx_update_irqs(gd54xx_t *gd54xx) +{ + if (!gd54xx->pci) + return; + + if ((gd54xx->vblank_irq > 0) && gd54xx_vga_vsync_enabled(gd54xx)) + pci_set_irq(gd54xx->card, PCI_INTA); + else + pci_clear_irq(gd54xx->card, PCI_INTA); +} + + +static void +gd54xx_vblank_start(svga_t *svga) +{ + gd54xx_t *gd54xx = (gd54xx_t*) svga->p; + if (gd54xx->vblank_irq >= 0) { + gd54xx->vblank_irq = 1; + gd54xx_update_irqs(gd54xx); + } +} + + /* Returns 1 if the card is a 5422+ */ static int gd54xx_is_5422(svga_t *svga) @@ -254,6 +530,92 @@ gd54xx_is_5422(svga_t *svga) } +static void +gd54xx_overlay_draw(svga_t *svga, int displine) +{ + gd54xx_t *gd54xx = (gd54xx_t *) svga->p; + int shift = (svga->crtc[0x27] >= CIRRUS_ID_CLGD5446) ? 2 : 0; + int h_acc = svga->overlay_latch.h_acc; + int r[8], g[8], b[8]; + int x_read = 4, x_write = 4; + int x; + uint32_t *p; + uint8_t *src = &svga->vram[(svga->overlay_latch.addr << shift) & svga->vram_mask]; + int bpp = svga->bpp; + int bytesperpix = (bpp + 7) / 8; + uint8_t *src2 = &svga->vram[(svga->ma - (svga->hdisp * bytesperpix)) & svga->vram_display_mask]; + int w = gd54xx->overlay.r2sdz; + int occl, ckval; + + if (gd54xx->overlay.mode == 2) + w *= 4; + else + w *= 2; + + p = &((uint32_t *)buffer32->line[displine])[gd54xx->overlay.region1size + svga->x_add]; + src2 += gd54xx->overlay.region1size * bytesperpix; + + OVERLAY_SAMPLE(); + + for (x = 0; (x < gd54xx->overlay.region2size) && + ((x + gd54xx->overlay.region1size) < svga->hdisp); x++) { + if (gd54xx->overlay.occlusion) { + occl = 1; + ckval = gd54xx->overlay.ck; + if (bytesperpix == 1) { + if (*src2 == ckval) + occl = 0; + } else if (bytesperpix == 2) { + if (*((uint16_t*)src2) == ckval) + occl = 0; + } else + occl = 0; + if (!occl) + *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); + src2 += bytesperpix; + } else + *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); + + h_acc += gd54xx->overlay.hzoom; + if (h_acc >= 256) { + if ((x_read ^ (x_read + 1)) & ~3) + OVERLAY_SAMPLE(); + x_read = (x_read + 1) & 7; + + h_acc -= 256; + } + } + + svga->overlay_latch.v_acc += gd54xx->overlay.vzoom; + if (svga->overlay_latch.v_acc >= 256) { + svga->overlay_latch.v_acc -= 256; + svga->overlay_latch.addr += svga->overlay.pitch << 1; + } +} + + +static void +gd54xx_update_overlay(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + int bpp = svga->bpp; + + svga->overlay.ysize = gd54xx->overlay.wve - gd54xx->overlay.wvs + 1; + gd54xx->overlay.region1size = 32 * gd54xx->overlay.r1sz / bpp + (gd54xx->overlay.r1adjust * 8 / bpp); + gd54xx->overlay.region2size = 32 * gd54xx->overlay.r2sz / bpp + (gd54xx->overlay.r2adjust * 8 / bpp); + + gd54xx->overlay.occlusion = (svga->crtc[0x3e] & 0x80) != 0 && svga->bpp <= 16; + + /* Mask and chroma key ignored. */ + if (gd54xx->overlay.colorkeymode == 0) + gd54xx->overlay.ck = gd54xx->overlay.colorkeycompare; + else if (gd54xx->overlay.colorkeymode == 1) + gd54xx->overlay.ck = gd54xx->overlay.colorkeycompare | (gd54xx->overlay.colorkeycomparemask << 8); + else + gd54xx->overlay.occlusion = 0; +} + + /* Returns 1 if the card supports the 8-bpp/16-bpp transparency color or mask. */ static int gd54xx_has_transp(svga_t *svga, int mask) @@ -538,6 +900,15 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) gd54xx_recalc_banking(gd54xx); break; + case 0x0c: + gd54xx->overlay.colorkeycompare = val; + gd54xx_update_overlay(gd54xx); + break; + case 0x0d: + gd54xx->overlay.colorkeycomparemask = val; + gd54xx_update_overlay(gd54xx); + break; + case 0x10: gd543x_mmio_write(0xb8001, val, gd54xx); break; @@ -640,7 +1011,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) } return; case 0x3d4: - svga->crtcreg = val & 0x3f; + svga->crtcreg = val & gd54xx->crtcreg_mask; return; case 0x3d5: if (((svga->crtcreg == 0x19) || (svga->crtcreg == 0x1a) || @@ -655,7 +1026,104 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; + if (svga->crtcreg == 0x11) { + if (!(val & 0x10)) { + if (gd54xx->vblank_irq > 0) + gd54xx->vblank_irq = -1; + } else if (gd54xx->vblank_irq < 0) + gd54xx->vblank_irq = 0; + gd54xx_update_irqs(gd54xx); + if ((val & ~0x30) == (old & ~0x30)) + old = val; + } + if (old != val) { + /* Overlay registers */ + switch (svga->crtcreg) { + case 0x1d: + if (((old >> 3) & 7) != ((val >> 3) & 7)) { + gd54xx->overlay.colorkeymode = (val >> 3) & 7; + gd54xx_update_overlay(gd54xx); + } + break; + case 0x31: + gd54xx->overlay.hzoom = val == 0 ? 256 : val; + gd54xx_update_overlay(gd54xx); + break; + case 0x32: + gd54xx->overlay.vzoom = val == 0 ? 256 : val; + gd54xx_update_overlay(gd54xx); + break; + case 0x33: + gd54xx->overlay.r1sz &= ~0xff; + gd54xx->overlay.r1sz |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x34: + gd54xx->overlay.r2sz &= ~0xff; + gd54xx->overlay.r2sz |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x35: + gd54xx->overlay.r2sdz &= ~0xff; + gd54xx->overlay.r2sdz |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x36: + gd54xx->overlay.r1sz &= 0xff; + gd54xx->overlay.r1sz |= (val << 8) & 0x300; + gd54xx->overlay.r2sz &= 0xff; + gd54xx->overlay.r2sz |= (val << 6) & 0x300; + gd54xx->overlay.r2sdz &= 0xff; + gd54xx->overlay.r2sdz |= (val << 4) & 0x300; + gd54xx_update_overlay(gd54xx); + break; + case 0x37: + gd54xx->overlay.wvs &= ~0xff; + gd54xx->overlay.wvs |= val; + svga->overlay.y = gd54xx->overlay.wvs; + break; + case 0x38: + gd54xx->overlay.wve &= ~0xff; + gd54xx->overlay.wve |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x39: + gd54xx->overlay.wvs &= 0xff; + gd54xx->overlay.wvs |= (val << 8) & 0x300; + gd54xx->overlay.wve &= 0xff; + gd54xx->overlay.wve |= (val << 6) & 0x300; + gd54xx_update_overlay(gd54xx); + break; + case 0x3a: + svga->overlay.addr &= ~0xff; + svga->overlay.addr |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x3b: + svga->overlay.addr &= ~0xff00; + svga->overlay.addr |= val << 8; + gd54xx_update_overlay(gd54xx); + break; + case 0x3c: + svga->overlay.addr &= ~0x0f0000; + svga->overlay.addr |= (val << 16) & 0x0f0000; + svga->overlay.pitch &= ~0x100; + svga->overlay.pitch |= (val & 0x20) << 3; + gd54xx_update_overlay(gd54xx); + break; + case 0x3d: + svga->overlay.pitch &= ~0xff; + svga->overlay.pitch |= val; + gd54xx_update_overlay(gd54xx); + break; + case 0x3e: + gd54xx->overlay.mode = (val >> 1) & 7; + svga->overlay.ena = (val & 1) != 0; + gd54xx_update_overlay(gd54xx); + break; + } + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -679,6 +1147,11 @@ gd54xx_in(uint16_t addr, void *p) addr ^= 0x60; switch (addr) { + case 0x3c2: + ret = svga_in(addr, svga); + ret |= gd54xx->vblank_irq > 0 ? 0x80 : 0x00; + break; + case 0x3c4: if (svga->seqregs[6] == 0x12) { ret = svga->seqaddr; @@ -911,6 +1384,12 @@ gd54xx_in(uint16_t addr, void *p) case 0x39: ret = gd543x_mmio_read(0xb8021, gd54xx); break; + + case 0x3f: + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5446) + gd54xx->vportsync = !gd54xx->vportsync; + ret = gd54xx->vportsync ? 0x80 : 0x00; + break; } } else { if ((svga->gdcaddr < 2) && !gd54xx->unlocked) @@ -1056,7 +1535,9 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) } } else if (gd54xx->pci) { base = gd54xx->lfb_base; - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + /* if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) + size = 32 * 1024 * 1024; + else */ if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) size = 16 * 1024 * 1024; else size = 4 * 1024 * 1024; @@ -1080,9 +1561,12 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_APERTURE2) && ((gd54xx->blt.mode & (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC)) == - (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC))) - mem_mapping_set_addr(&gd54xx->aperture2_mapping, 0xbc000, 0x04000); - else + (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC))) { + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) + mem_mapping_set_addr(&gd54xx->aperture2_mapping, gd54xx->lfb_base + (16777216), 16777216); + else + mem_mapping_set_addr(&gd54xx->aperture2_mapping, 0xbc000, 0x04000); + } else mem_mapping_disable(&gd54xx->aperture2_mapping); } } @@ -1093,15 +1577,19 @@ gd54xx_recalctimings(svga_t *svga) { gd54xx_t *gd54xx = (gd54xx_t *)svga->p; uint8_t clocksel, rdmask; + uint8_t linedbl = svga->dispend * 9 / 10 >= svga->hdisp; svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); svga->interlace = (svga->crtc[0x1a] & 0x01); svga->map8 = svga->pallook; - if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) - svga->render = svga_render_8bpp_highres; - else if (svga->gdcreg[5] & 0x40) + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) { + if (linedbl) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + } else if (svga->gdcreg[5] & 0x40) svga->render = svga_render_8bpp_lowres; svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); @@ -1118,39 +1606,61 @@ gd54xx_recalctimings(svga_t *svga) switch (gd54xx->ramdac.ctrl & rdmask) { case 0: svga->bpp = 15; - if (gd54xx->ramdac.ctrl & 0x10) - svga->render = svga_render_15bpp_mix_highres; - else - svga->render = svga_render_15bpp_highres; + if (linedbl) { + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_lowres; + else + svga->render = svga_render_15bpp_lowres; + } else { + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_highres; + else + svga->render = svga_render_15bpp_highres; + } break; case 1: svga->bpp = 16; - svga->render = svga_render_16bpp_highres; + if (linedbl) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; break; case 5: if (gd54xx_is_5434(svga) && (svga->seqregs[7] & CIRRUS_SR7_BPP_32)) { svga->bpp = 32; - svga->render = svga_render_32bpp_highres; + if (linedbl) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) svga->rowoffset *= 2; } else { svga->bpp = 24; - svga->render = svga_render_24bpp_highres; + if (linedbl) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; } break; case 8: svga->bpp = 8; svga->map8 = video_8togs; - svga->render = svga_render_8bpp_highres; + if (linedbl) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; break; case 9: svga->bpp = 8; svga->map8 = video_8to32; - svga->render = svga_render_8bpp_highres; + if (linedbl) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; break; case 0xf: @@ -1158,41 +1668,63 @@ gd54xx_recalctimings(svga_t *svga) case CIRRUS_SR7_BPP_32: if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5430) { svga->bpp = 32; - svga->render = svga_render_32bpp_highres; + if (linedbl) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; svga->rowoffset *= 2; } break; case CIRRUS_SR7_BPP_24: svga->bpp = 24; - svga->render = svga_render_24bpp_highres; + if (linedbl) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; break; case CIRRUS_SR7_BPP_16: if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5428) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5426)) { svga->bpp = 16; - svga->render = svga_render_16bpp_highres; + if (linedbl) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; } break; case CIRRUS_SR7_BPP_16_DOUBLEVCLK: svga->bpp = 16; - svga->render = svga_render_16bpp_highres; + if (linedbl) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; break; case CIRRUS_SR7_BPP_8: svga->bpp = 8; - svga->render = svga_render_8bpp_highres; + if (linedbl) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; break; } break; } } else { svga->bpp = 15; - if (gd54xx->ramdac.ctrl & 0x10) - svga->render = svga_render_15bpp_mix_highres; - else - svga->render = svga_render_15bpp_highres; + if (linedbl) { + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_lowres; + else + svga->render = svga_render_15bpp_lowres; + } else { + if (gd54xx->ramdac.ctrl & 0x10) + svga->render = svga_render_15bpp_mix_highres; + else + svga->render = svga_render_15bpp_highres; + } } } @@ -1233,16 +1765,19 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; uint32_t bgcol = gd54xx->extpallook[0x00]; uint32_t fgcol = gd54xx->extpallook[0x0f]; + uint8_t linedbl = svga->dispend * 9 / 10 >= svga->hdisp; + + offset <<= linedbl; if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += pitch; for (x = 0; x < svga->hwcursor.xsize; x += 8) { - dat[0] = svga->vram[svga->hwcursor_latch.addr]; + dat[0] = svga->vram[svga->hwcursor_latch.addr & svga->vram_display_mask]; if (svga->hwcursor.xsize == 64) - dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; + dat[1] = svga->vram[(svga->hwcursor_latch.addr + 0x08) & svga->vram_display_mask]; else - dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + dat[1] = svga->vram[(svga->hwcursor_latch.addr + 0x80) & svga->vram_display_mask]; for (xx = 0; xx < 8; xx++) { b0 = (dat[0] >> (7 - xx)) & 1; b1 = (dat[1] >> (7 - xx)) & 1; @@ -2451,6 +2986,98 @@ gd543x_mmio_readl(uint32_t addr, void *p) } +static void +gd5480_vgablt_write(uint32_t addr, uint8_t val, void *p) +{ + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + gd543x_mmio_writeb((addr & 0x000000ff) | 0x000b8000, val, p); + else if (addr < 0x00000100) + gd54xx_out(0x03c0 + addr, val, p); +} + + +static void +gd5480_vgablt_writew(uint32_t addr, uint16_t val, void *p) +{ + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + gd543x_mmio_writew((addr & 0x000000ff) | 0x000b8000, val, p); + else if (addr < 0x00000100) { + gd5480_vgablt_write(addr, val & 0xff, p); + gd5480_vgablt_write(addr + 1, val >> 8, p); + } +} + + +static void +gd5480_vgablt_writel(uint32_t addr, uint32_t val, void *p) +{ + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + gd543x_mmio_writel((addr & 0x000000ff) | 0x000b8000, val, p); + else if (addr < 0x00000100) { + gd5480_vgablt_writew(addr, val & 0xffff, p); + gd5480_vgablt_writew(addr + 2, val >> 16, p); + } +} + + +static uint8_t +gd5480_vgablt_read(uint32_t addr, void *p) +{ + uint8_t ret = 0xff; + + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + ret = gd543x_mmio_read((addr & 0x000000ff) | 0x000b8000, p); + else if (addr < 0x00000100) + ret = gd54xx_in(0x03c0 + addr, p); + + return ret; +} + + +static uint16_t +gd5480_vgablt_readw(uint32_t addr, void *p) +{ + uint16_t ret = 0xffff; + + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + ret = gd543x_mmio_readw((addr & 0x000000ff) | 0x000b8000, p); + else if (addr < 0x00000100) { + ret = gd5480_vgablt_read(addr, p); + ret |= (gd5480_vgablt_read(addr + 1, p) << 8); + } + + return ret; +} + + +static uint32_t +gd5480_vgablt_readl(uint32_t addr, void *p) +{ + uint32_t ret = 0xffffffff; + + addr &= 0x00000fff; + + if ((addr >= 0x00000100) && (addr < 0x00000200)) + ret = gd543x_mmio_readl((addr & 0x000000ff) | 0x000b8000, p); + else if (addr < 0x00000100) { + ret = gd5480_vgablt_readw(addr, p); + ret |= (gd5480_vgablt_readw(addr + 2, p) << 16); + } + + return ret; +} + + static uint8_t gd54xx_color_expand(gd54xx_t *gd54xx, int mask, int shift) { @@ -2947,6 +3574,21 @@ cl_pci_read(int func, int addr, void *p) break; case 0x13: ret = gd54xx->lfb_base >> 24; + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) + ret = 0xfe; + break; + + case 0x14: + ret = 0x00; /*PCI VGA/BitBLT Register Base Address*/ + break; + case 0x15: + ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? ((gd54xx->vgablt_base >> 8) & 0xf0) : 0x00; + break; + case 0x16: + ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? ((gd54xx->vgablt_base >> 16) & 0xff) : 0x00; + break; + case 0x17: + ret = (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) ? ((gd54xx->vgablt_base >> 24) & 0xff) : 0x00; break; case 0x30: @@ -2978,6 +3620,8 @@ static void cl_pci_write(int func, int addr, uint8_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + uint32_t byte; if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) return; @@ -2985,17 +3629,37 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) switch (addr) { case PCI_REG_COMMAND: gd54xx->pci_regs[PCI_REG_COMMAND] = val & 0x23; + mem_mapping_disable(&gd54xx->vgablt_mapping); io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); if (val & PCI_COMMAND_IO) io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + if ((val & PCI_COMMAND_MEM) && (gd54xx->vgablt_base != 0x00000000) && (gd54xx->vgablt_base < 0xfff00000)) + mem_mapping_set_addr(&gd54xx->vgablt_mapping, gd54xx->vgablt_base, 0x1000); gd543x_recalc_mapping(gd54xx); break; - case 0x13: + case 0x13: + /* 5480, like 5446 rev. B, has a 32 MB aperture, with the second set used for + BitBLT transfers. */ + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5480) + val &= 0xfe; gd54xx->lfb_base = val << 24; gd543x_recalc_mapping(gd54xx); break; + case 0x15: case 0x16: case 0x17: + if (svga->crtc[0x27] != CIRRUS_ID_CLGD5480) + return; + byte = (addr & 3) << 3; + gd54xx->vgablt_base &= ~(0xff << byte); + if (addr == 0x15) + val &= 0xf0; + gd54xx->vgablt_base |= (val << byte); + mem_mapping_disable(&gd54xx->vgablt_mapping); + if ((gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM) && (gd54xx->vgablt_base != 0x00000000) && (gd54xx->vgablt_base < 0xfff00000)) + mem_mapping_set_addr(&gd54xx->vgablt_mapping, gd54xx->vgablt_base, 0x1000); + break; + case 0x30: case 0x32: case 0x33: gd54xx->pci_regs[addr] = val; if (gd54xx->pci_regs[0x30] & 0x01) { @@ -3173,7 +3837,6 @@ static void if (romfn) rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - if (info->flags & DEVICE_ISA) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_isa); else if (info->flags & DEVICE_PCI) @@ -3181,9 +3844,16 @@ static void else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_vlb); - svga_init(info, &gd54xx->svga, gd54xx, gd54xx->vram_size, - gd54xx_recalctimings, gd54xx_in, gd54xx_out, - gd54xx_hwcursor_draw, NULL); + if (id >= CIRRUS_ID_CLGD5426) { + svga_init(info, &gd54xx->svga, gd54xx, gd54xx->vram_size, + gd54xx_recalctimings, gd54xx_in, gd54xx_out, + gd54xx_hwcursor_draw, gd54xx_overlay_draw); + } else { + svga_init(info, &gd54xx->svga, gd54xx, gd54xx->vram_size, + gd54xx_recalctimings, gd54xx_in, gd54xx_out, + gd54xx_hwcursor_draw, NULL); + } + svga->vblank_start = gd54xx_vblank_start; svga->ven_write = gd54xx_write_modes45; if (vram <= 1) svga->decode_mask = gd54xx->vram_mask; @@ -3202,6 +3872,10 @@ static void gd5436_aperture2_readb, gd5436_aperture2_readw, gd5436_aperture2_readl, gd5436_aperture2_writeb, gd5436_aperture2_writew, gd5436_aperture2_writel, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_add(&gd54xx->vgablt_mapping, 0, 0, + gd5480_vgablt_read, gd5480_vgablt_readw, gd5480_vgablt_readl, + gd5480_vgablt_write, gd5480_vgablt_writew, gd5480_vgablt_writel, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); } else { mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, NULL, gd54xx_write, gd54xx_writew, NULL); mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, @@ -3216,11 +3890,16 @@ static void gd5436_aperture2_readb, gd5436_aperture2_readw, NULL, gd5436_aperture2_writeb, gd5436_aperture2_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_add(&gd54xx->vgablt_mapping, 0, 0, + gd5480_vgablt_read, gd5480_vgablt_readw, NULL, + gd5480_vgablt_write, gd5480_vgablt_writew, NULL, + NULL, MEM_MAPPING_EXTERNAL, gd54xx); } mem_mapping_set_p(&svga->mapping, gd54xx); mem_mapping_disable(&gd54xx->mmio_mapping); mem_mapping_disable(&gd54xx->linear_mapping); mem_mapping_disable(&gd54xx->aperture2_mapping); + mem_mapping_disable(&gd54xx->vgablt_mapping); io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); @@ -3274,6 +3953,13 @@ static void gd54xx->ddc = ddc_init(i2c_gpio_get_bus(gd54xx->i2c)); } + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5446) + gd54xx->crtcreg_mask = 0x7f; + else + gd54xx->crtcreg_mask = 0x3f; + + gd54xx->overlay.colorkeycompare = 0xff; + return gd54xx; } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index efe663d8c..0e1511af4 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1063,8 +1063,6 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) switch (svga->writemode) { case 0: val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); - // if (svga->gdcreg[3] & 7) - // val = svga_rotate[svga->gdcreg[3] & 7][val]; if ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { for (i = 0; i < count; i++) { if ((svga->adv_flags & FLAG_EXT_WRITE) && (svga->adv_flags & FLAG_ADDR_BY8)) { @@ -1115,8 +1113,6 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) break; case 3: val = ((val >> (svga->gdcreg[3] & 7)) | (val << (8 - (svga->gdcreg[3] & 7)))); - // if (svga->gdcreg[3] & 7) - // val = svga_rotate[svga->gdcreg[3] & 7][val]; wm = svga->gdcreg[8]; svga->gdcreg[8] &= val; From bdd4499eb3b27952ef3d056c1cb2cf6f903077d6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 28 Nov 2020 07:03:57 +0100 Subject: [PATCH 55/67] Added support for loading ROM's with even bytes followed by odd bytes in the same file. --- src/mem/rom.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/mem/rom.c b/src/mem/rom.c index fc827539b..8e4eda437 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -162,6 +162,42 @@ rom_readl(uint32_t addr, void *priv) } +int +rom_load_linear_oddeven(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) +{ + FILE *f = rom_fopen(fn, L"rb"); + int i; + + if (f == NULL) { + rom_log("ROM: image '%ls' not found\n", fn); + return(0); + } + + /* Make sure we only look at the base-256K offset. */ + if (addr >= 0x40000) + addr = 0; + else + addr &= 0x03ffff; + + if (ptr != NULL) { + if (fseek(f, off, SEEK_SET) == -1) + fatal("rom_load_linear(): Error seeking to the beginning of the file\n"); + for (i = 0; i < (sz >> 1); i++) { + if (fread(ptr + (addr + (i << 1)), 1, 1, f) != 1) + fatal("rom_load_linear(): Error reading even data\n"); + } + for (i = 0; i < (sz >> 1); i++) { + if (fread(ptr + (addr + (i << 1) + 1), 1, 1, f) != 1) + fatal("rom_load_linear(): Error reading od data\n"); + } + } + + (void)fclose(f); + + return(1); +} + + /* Load a ROM BIOS from its chips, interleaved mode. */ int rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) @@ -507,6 +543,36 @@ rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint } +int +rom_init_oddeven(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags) +{ + rom_log("rom_init(%08X, %08X, %08X, %08X, %08X, %08X, %08X)\n", rom, fn, addr, sz, mask, off, flags); + + /* Allocate a buffer for the image. */ + rom->rom = malloc(sz); + memset(rom->rom, 0xff, sz); + + /* Load the image file into the buffer. */ + if (! rom_load_linear_oddeven(fn, addr, sz, off, rom->rom)) { + /* Nope.. clean up. */ + free(rom->rom); + rom->rom = NULL; + return(-1); + } + + rom->sz = sz; + rom->mask = mask; + + mem_mapping_add(&rom->mapping, + addr, sz, + rom_read, rom_readw, rom_readl, + mem_write_null, mem_write_nullw, mem_write_nulll, + rom->rom, flags | MEM_MAPPING_ROM, rom); + + return(0); +} + + int rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int mask, int off, uint32_t flags) { From 19e093e554aee459f89befb2a65b4ed5351b9ee8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 28 Nov 2020 07:04:40 +0100 Subject: [PATCH 56/67] Renderer fixes and improvements. --- src/include/86box/86box.h | 1 + src/include/86box/rom.h | 4 + src/include/86box/win.h | 3 +- src/include/86box/win_sdl.h | 5 +- src/pc.c | 7 + src/win/win.c | 88 +++++----- src/win/win_sdl.c | 323 ++++++++++++++---------------------- src/win/win_ui.c | 239 ++++++++++++++------------ 8 files changed, 313 insertions(+), 357 deletions(-) diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 627a293c6..297c60c99 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -152,6 +152,7 @@ extern void pclog_toggle_suppr(void); extern void pclog(const char *fmt, ...); extern void fatal(const char *fmt, ...); extern void set_screen_size(int x, int y); +extern void reset_screen_size(void); extern void set_screen_size_natural(void); #if 0 extern void pc_reload(wchar_t *fn); diff --git a/src/include/86box/rom.h b/src/include/86box/rom.h index ee9d9e95f..d06864ca0 100644 --- a/src/include/86box/rom.h +++ b/src/include/86box/rom.h @@ -49,6 +49,8 @@ extern FILE *rom_fopen(wchar_t *fn, wchar_t *mode); extern int rom_getfile(wchar_t *fn, wchar_t *s, int size); extern int rom_present(wchar_t *fn); +extern int rom_load_linear_oddeven(wchar_t *fn, uint32_t addr, int sz, + int off, uint8_t *ptr); extern int rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr); extern int rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, @@ -68,6 +70,8 @@ extern int bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, extern int rom_init(rom_t *rom, wchar_t *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); +extern int rom_init_oddeven(rom_t *rom, wchar_t *fn, uint32_t address, int size, + int mask, int file_offset, uint32_t flags); extern int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, wchar_t *fn_high, uint32_t address, int size, int mask, int file_offset, diff --git a/src/include/86box/win.h b/src/include/86box/win.h index 4aceae0be..ceb06f1ba 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -55,6 +55,8 @@ DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); #define SB_CLASS_NAME L"86BoxStatusBar" #define SB_MENU_NAME L"StatusBarMenu" #define FS_CLASS_NAME L"86BoxFullScreen" +#define SDL_CLASS_NAME L"86BoxSDLWnd" +#define SDL_SUB_CLASS_NAME L"86BoxSDLSubWnd" #define FLOPPY_SUBMENU_NAME L"FloppySubmenu" #define CDROM_SUBMENU_NAME L"CdromSubmenu" @@ -155,7 +157,6 @@ extern int hard_disk_was_added(void); /* Platform UI support functions. */ extern int ui_init(int nCmdShow); -extern void plat_set_input(HWND h); /* Functions in win_about.c: */ diff --git a/src/include/86box/win_sdl.h b/src/include/86box/win_sdl.h index 4f6bca231..cc61142be 100644 --- a/src/include/86box/win_sdl.h +++ b/src/include/86box/win_sdl.h @@ -54,13 +54,10 @@ extern void sdl_close(void); extern int sdl_inits(HWND h); extern int sdl_inith(HWND h); extern int sdl_initho(HWND h); -extern int sdl_inits_fs(HWND h); -extern int sdl_inith_fs(HWND h); -extern int sdl_initho_fs(HWND h); extern int sdl_pause(void); extern void sdl_resize(int x, int y); extern void sdl_enable(int enable); -extern void sdl_reinit_texture(); +extern void sdl_set_fs(int fs); #endif /*WIN_SDL_H*/ diff --git a/src/pc.c b/src/pc.c index 1f25eba14..31586a4b3 100644 --- a/src/pc.c +++ b/src/pc.c @@ -1132,6 +1132,13 @@ set_screen_size(int x, int y) } +void +reset_screen_size(void) +{ + set_screen_size(unscaled_size_x, efscrnsz_y); +} + + void set_screen_size_natural(void) { diff --git a/src/win/win.c b/src/win/win.c index 0d465f2f3..50c87d015 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -86,23 +86,14 @@ static const struct { void (*resize)(int x, int y); int (*pause)(void); void (*enable)(int enable); -} vid_apis[2][RENDERERS_NUM] = { - { - { "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable }, - { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable }, - { "SDL_OpenGL", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable } + void (*set_fs)(int fs); +} vid_apis[RENDERERS_NUM] = { + { "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs }, + { "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs }, + { "SDL_OpenGL", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs } #ifdef USE_VNC - ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL } + ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL, NULL } #endif - }, - { - { "SDL_Software", 1, (int(*)(void*))sdl_inits_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable }, - { "SDL_Hardware", 1, (int(*)(void*))sdl_inith_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable }, - { "SDL_OpenGL", 1, (int(*)(void*))sdl_initho_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable } -#ifdef USE_VNC - ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL } -#endif - }, }; @@ -681,8 +672,8 @@ plat_vidapi(char *name) if (!strcasecmp(name, "ddraw") || !strcasecmp(name, "sdl")) return(1); for (i = 0; i < RENDERERS_NUM; i++) { - if (vid_apis[0][i].name && - !strcasecmp(vid_apis[0][i].name, name)) return(i); + if (vid_apis[i].name && + !strcasecmp(vid_apis[i].name, name)) return(i); } /* Default value. */ @@ -730,16 +721,16 @@ plat_setvid(int api) video_wait_for_blit(); /* Close the (old) API. */ - vid_apis[0][vid_api].close(); + vid_apis[vid_api].close(); vid_api = api; - if (vid_apis[0][vid_api].local) + if (vid_apis[vid_api].local) ShowWindow(hwndRender, SW_SHOW); else ShowWindow(hwndRender, SW_HIDE); /* Initialize the (new) API. */ - i = vid_apis[0][vid_api].init((void *)hwndRender); + i = vid_apis[vid_api].init((void *)hwndRender); endblit(); if (! i) return(0); @@ -755,11 +746,11 @@ plat_setvid(int api) void plat_vidsize(int x, int y) { - if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].resize) return; + if (!vid_api_inited || !vid_apis[vid_api].resize) return; startblit(); video_wait_for_blit(); - vid_apis[video_fullscreen][vid_api].resize(x, y); + vid_apis[vid_api].resize(x, y); endblit(); } @@ -769,66 +760,61 @@ plat_vidapi_enable(int enable) { int i = 1; - if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].enable) return; + if (!vid_api_inited || !vid_apis[vid_api].enable) + return; - startblit(); video_wait_for_blit(); + vid_apis[vid_api].enable(enable != 0); - vid_apis[video_fullscreen][vid_api].enable(enable & 1); + if (! i) + return; - endblit(); - - if (! i) return; - - if (enable) + if (enable) device_force_redraw(); } + int get_vidpause(void) { - return(vid_apis[video_fullscreen][vid_api].pause()); + return(vid_apis[vid_api].pause()); } void plat_setfullscreen(int on) { - HWND *hw; - - /* Want off and already off? */ - if (!on && !video_fullscreen) return; - - /* Want on and already on? */ - if (on && video_fullscreen) return; + /* Are we changing from the same state to the same state? */ + if ((!!on) == (!!video_fullscreen)) + return; if (on && video_fullscreen_first) { + video_fullscreen |= 2; if (ui_msgbox_header(MBX_INFO | MBX_DONTASK, (wchar_t *) IDS_2134, (wchar_t *) IDS_2052) == 10) { video_fullscreen_first = 0; config_save(); } + video_fullscreen &= 1; } /* OK, claim the video. */ - startblit(); video_wait_for_blit(); - - plat_vidapi_enable(0); - win_mouse_close(); /* Close the current mode, and open the new one. */ - vid_apis[video_fullscreen][vid_api].close(); - video_fullscreen = on; - hw = (video_fullscreen) ? &hwndMain : &hwndRender; - vid_apis[video_fullscreen][vid_api].init((void *) *hw); + video_fullscreen = on | 2; + if (vid_apis[vid_api].set_fs) + vid_apis[vid_api].set_fs(on); + if (!on) + plat_resize(scrnsz_x, scrnsz_y); + video_fullscreen &= 1; + video_force_resize_set(1); + if (!on) + doresize = 1; win_mouse_init(); - plat_vidapi_enable(1); - /* Release video and make it redraw the screen. */ - endblit(); device_force_redraw(); /* Send a CTRL break code so CTRL does not get stuck. */ @@ -837,6 +823,10 @@ plat_setfullscreen(int on) /* Finally, handle the host's mouse cursor. */ /* win_log("%s full screen, %s cursor\n", on ? "enter" : "leave", on ? "hide" : "show"); */ show_cursor(video_fullscreen ? 0 : -1); + + /* This is needed for OpenGL. */ + plat_vidapi_enable(0); + plat_vidapi_enable(1); } diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index db12f2cc8..7e29d6381 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -82,7 +82,6 @@ static SDL_Window *sdl_win = NULL; static SDL_Renderer *sdl_render = NULL; static SDL_Texture *sdl_tex = NULL; static HWND sdl_parent_hwnd = NULL; -static HWND sdl_hwnd = NULL; static int sdl_w, sdl_h; static int sdl_fs, sdl_flags = -1; static int cur_w, cur_h; @@ -181,6 +180,7 @@ sdl_stretch(int *w, int *h, int *x, int *y) switch (video_fullscreen_scale) { case FULLSCR_SCALE_FULL: + default: *w = sdl_w; *h = sdl_h; *x = 0; @@ -225,8 +225,6 @@ sdl_stretch(int *w, int *h, int *x, int *y) *y = (int) dy; break; } - - sdl_reinit_texture(); } @@ -236,17 +234,7 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) SDL_Rect r_src; int ret; - if (!sdl_enabled) { - video_blit_complete(); - return; - } - - if ((y1 == y2) || (h <= 0)) { - video_blit_complete(); - return; - } - - if (render_buffer == NULL) { + if (!sdl_enabled || (y1 == y2) || (h <= 0) || (render_buffer == NULL)) { video_blit_complete(); return; } @@ -260,13 +248,6 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) SDL_UpdateTexture(sdl_tex, &r_src, &(render_buffer->dat)[y1 * w], w * 4); video_blit_complete(); - if (sdl_fs) { - sdl_log("sdl_blit(%i, %i, %i, %i, %i, %i) (%i, %i)\n", x, y, y1, y2, w, h, unscaled_size_x, efscrnsz_y); - if (w == unscaled_size_x) - sdl_resize(w, h); - sdl_log("(%08X, %08X, %08X)\n", sdl_win, sdl_render, sdl_tex); - } - SDL_RenderClear(sdl_render); r_src.x = 0; @@ -279,11 +260,31 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) sdl_log("SDL: unable to copy texture to renderer (%s)\n", sdl_GetError()); SDL_RenderPresent(sdl_render); - SDL_UnlockMutex(sdl_mutex); } +static void +sdl_destroy_window(void) +{ + if (sdl_win != NULL) { + SDL_DestroyWindow(sdl_win); + sdl_win = NULL; + } +} + + +static void +sdl_destroy_texture(void) +{ + /* SDL_DestroyRenderer also automatically destroys all associated textures. */ + if (sdl_render != NULL) { + SDL_DestroyRenderer(sdl_render); + sdl_render = NULL; + } +} + + void sdl_close(void) { @@ -300,32 +301,10 @@ sdl_close(void) sdl_mutex = NULL; } - if (sdl_tex != NULL) { - SDL_DestroyTexture(sdl_tex); - sdl_tex = NULL; - } - - if (sdl_render != NULL) { - SDL_DestroyRenderer(sdl_render); - sdl_render = NULL; - } - - if (sdl_win != NULL) { - SDL_DestroyWindow(sdl_win); - sdl_win = NULL; - } - - if (sdl_hwnd != NULL) { - plat_set_input(hwndMain); - - ShowWindow(hwndRender, TRUE); - - SetFocus(hwndMain); - - if (sdl_fs) - DestroyWindow(sdl_hwnd); - sdl_hwnd = NULL; - } + sdl_destroy_texture(); + sdl_destroy_window(); + ImmAssociateContext(hwndMain, NULL); + SetFocus(hwndMain); if (sdl_parent_hwnd != NULL) { DestroyWindow(sdl_parent_hwnd); @@ -334,7 +313,6 @@ sdl_close(void) /* Quit. */ SDL_Quit(); - sdl_flags = -1; } @@ -359,13 +337,87 @@ sdl_select_best_hw_driver(void) } +static void +sdl_reinit_texture(void) +{ + if (sdl_flags == -1) + return; + + sdl_destroy_texture(); + + if (sdl_flags & RENDERER_HARDWARE) { + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); + } else + sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + + sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, 2048, 2048); +} + + +void +sdl_set_fs(int fs) +{ + int w = 0, h = 0, x = 0, y = 0; + RECT rect; + + SDL_LockMutex(sdl_mutex); + sdl_enabled = 0; + sdl_destroy_texture(); + + if (fs) { + ShowWindow(sdl_parent_hwnd, TRUE); + SetParent(hwndRender, sdl_parent_hwnd); + ShowWindow(hwndRender, TRUE); + MoveWindow(sdl_parent_hwnd, 0, 0, sdl_w, sdl_h, TRUE); + + /* Show the window, make it topmost, and give it focus. */ + w = unscaled_size_x; + h = efscrnsz_y; + sdl_stretch(&w, &h, &x, &y); + MoveWindow(hwndRender, x, y, w, h, TRUE); + ImmAssociateContext(sdl_parent_hwnd, NULL); + SetFocus(sdl_parent_hwnd); + + /* Redirect RawInput to this new window. */ + old_capture = mouse_capture; + GetWindowRect(hwndRender, &rect); + ClipCursor(&rect); + mouse_capture = 1; + } else { + SetParent(hwndRender, hwndMain); + ShowWindow(sdl_parent_hwnd, FALSE); + ShowWindow(hwndRender, TRUE); + ImmAssociateContext(hwndMain, NULL); + SetFocus(hwndMain); + mouse_capture = old_capture; + + if (mouse_capture) { + GetWindowRect(hwndRender, &rect); + ClipCursor(&rect); + } else + ClipCursor(&oldclip); + } + + sdl_fs = fs; + + if (fs) + sdl_flags |= RENDERER_FULL_SCREEN; + else + sdl_flags &= ~RENDERER_FULL_SCREEN; + + sdl_reinit_texture(); + sdl_enabled = 1; + SDL_UnlockMutex(sdl_mutex); +} + + static int sdl_init_common(int flags) { wchar_t temp[128]; SDL_version ver; - int w = 0, h = 0, x = 0, y = 0; - RECT rect; sdl_log("SDL: init (fs=%d)\n", fs); @@ -386,111 +438,24 @@ sdl_init_common(int flags) sdl_select_best_hw_driver(); } - if (flags & RENDERER_FULL_SCREEN) { - /* Get the size of the (current) desktop. */ - sdl_w = GetSystemMetrics(SM_CXSCREEN); - sdl_h = GetSystemMetrics(SM_CYSCREEN); + /* Get the size of the (current) desktop. */ + sdl_w = GetSystemMetrics(SM_CXSCREEN); + sdl_h = GetSystemMetrics(SM_CYSCREEN); - /* Create the desktop-covering window. */ - _swprintf(temp, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); - sdl_parent_hwnd = CreateWindow(SUB_CLASS_NAME, - temp, - WS_POPUP, - 0, 0, sdl_w, sdl_h, - HWND_DESKTOP, - NULL, - hinstance, - NULL); + /* Create the desktop-covering window. */ + _swprintf(temp, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); + sdl_parent_hwnd = CreateWindow(SDL_CLASS_NAME, temp, WS_POPUP, 0, 0, sdl_w, sdl_h, + HWND_DESKTOP, NULL, hinstance, NULL); + ShowWindow(sdl_parent_hwnd, FALSE); - SetWindowPos(sdl_parent_hwnd, HWND_TOPMOST, - 0, 0, sdl_w, sdl_h, SWP_SHOWWINDOW); + sdl_flags = flags; - /* Create the actual rendering window. */ - _swprintf(temp, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); - sdl_hwnd = CreateWindow(SUB_CLASS_NAME, - temp, - WS_POPUP, - 0, 0, sdl_w, sdl_h, - sdl_parent_hwnd, - NULL, - hinstance, - NULL); - sdl_log("SDL: FS %dx%d window at %08lx\n", sdl_w, sdl_h, sdl_hwnd); - - /* Redirect RawInput to this new window. */ - plat_set_input(sdl_hwnd); - - SetFocus(sdl_hwnd); - - /* Show the window, make it topmost, and give it focus. */ - w = unscaled_size_x; - h = efscrnsz_y; - sdl_stretch(&w, &h, &x, &y); - SetWindowPos(sdl_hwnd, sdl_parent_hwnd, - x, y, w, h, SWP_SHOWWINDOW); - - /* Now create the SDL window from that. */ - sdl_win = SDL_CreateWindowFrom((void *)sdl_hwnd); - - old_capture = mouse_capture; - - GetWindowRect(sdl_hwnd, &rect); - - ClipCursor(&rect); - - mouse_capture = 1; - } else { - /* Create the SDL window from the render window. */ - sdl_win = SDL_CreateWindowFrom((void *)hwndRender); - - mouse_capture = old_capture; - - if (mouse_capture) { - GetWindowRect(hwndRender, &rect); - - ClipCursor(&rect); - } else { - ClipCursor(&oldclip); - } - } if (sdl_win == NULL) { sdl_log("SDL: unable to CreateWindowFrom (%s)\n", SDL_GetError()); - sdl_close(); - return(0); } - /* - * TODO: - * SDL_RENDERER_SOFTWARE, because SDL tries to do funky stuff - * otherwise (it turns off Win7 Aero and it looks like it's - * trying to switch to fullscreen even though the window is - * not a fullscreen window?) - */ - if (flags & RENDERER_HARDWARE) { - sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); - } else - sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); - - if (sdl_render == NULL) { - sdl_log("SDL: unable to create renderer (%s)\n", SDL_GetError()); - sdl_close(); - return(0); - } - - /* - * TODO: - * Actually the source is (apparently) XRGB8888, but the alpha - * channel seems to be set to 255 everywhere, so ARGB8888 works - * just as well. - */ - sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, 2048, 2048); - if (sdl_tex == NULL) { - sdl_log("SDL: unable to create texture (%s)\n", SDL_GetError()); - sdl_close(); - return(0); - } + sdl_win = SDL_CreateWindowFrom((void *)hwndRender); + sdl_set_fs(video_fullscreen & 1); /* Make sure we get a clean exit. */ atexit(sdl_close); @@ -498,14 +463,9 @@ sdl_init_common(int flags) /* Register our renderer! */ video_setblit(sdl_blit); - sdl_fs = !!(flags & RENDERER_FULL_SCREEN); - sdl_enabled = 1; - sdl_mutex = SDL_CreateMutex(); - sdl_flags = flags; - return(1); } @@ -531,47 +491,6 @@ sdl_initho(HWND h) } -int -sdl_inits_fs(HWND h) -{ - return sdl_init_common(RENDERER_FULL_SCREEN); -} - - -int -sdl_inith_fs(HWND h) -{ - return sdl_init_common(RENDERER_FULL_SCREEN | RENDERER_HARDWARE); -} - - -int -sdl_initho_fs(HWND h) -{ - return sdl_init_common(RENDERER_FULL_SCREEN | RENDERER_HARDWARE | RENDERER_OPENGL); -} - - -void -sdl_reinit_texture() -{ - if ((sdl_render == NULL) || (sdl_flags == -1)) - return; - - SDL_DestroyTexture(sdl_tex); - SDL_DestroyRenderer(sdl_render); - if (sdl_flags & RENDERER_HARDWARE) { - sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); - } else - sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); - sdl_tex = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, 2048, 2048); - SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); - SDL_SetWindowPosition(sdl_win, cur_wx, cur_wy); -} - - int sdl_pause(void) { @@ -584,6 +503,9 @@ sdl_resize(int x, int y) { int ww = 0, wh = 0, wx = 0, wy = 0; + if (video_fullscreen & 2) + return; + if ((x == cur_w) && (y == cur_h)) return; @@ -594,7 +516,7 @@ sdl_resize(int x, int y) if (sdl_fs) { sdl_stretch(&ww, &wh, &wx, &wy); - MoveWindow(sdl_hwnd, wx, wy, ww, wh, TRUE); + MoveWindow(hwndRender, wx, wy, ww, wh, TRUE); } cur_w = x; @@ -605,6 +527,9 @@ sdl_resize(int x, int y) cur_ww = ww; cur_wh = wh; + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); + SDL_SetWindowPosition(sdl_win, cur_wx, cur_wy); + sdl_reinit_texture(); SDL_UnlockMutex(sdl_mutex); @@ -619,7 +544,11 @@ sdl_enable(int enable) SDL_LockMutex(sdl_mutex); sdl_enabled = enable; - if (enable) + + if (enable == 1) { + SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); sdl_reinit_texture(); + } + SDL_UnlockMutex(sdl_mutex); } diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 5dd4026c5..f4cf7047f 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -28,6 +28,7 @@ #include #include #include +#include <86box/plat.h> #include <86box/86box.h> #include <86box/config.h> #include "../cpu/cpu.h" @@ -38,7 +39,6 @@ #include <86box/nvr.h> #include <86box/video.h> #include <86box/vid_ega.h> // for update_overscan -#include <86box/plat.h> #include <86box/plat_midi.h> #include <86box/plat_dynld.h> #include <86box/ui.h> @@ -373,6 +373,85 @@ plat_power_off(void) } +/* Catch WM_INPUT messages for 'current focus' window. */ +#if defined(__amd64__) || defined(__aarch64__) +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +input_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_INPUT: + if (infocus) { + UINT size = 0; + PRAWINPUT raw = NULL; + + /* Here we read the raw input data */ + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + raw = (PRAWINPUT)malloc(size); + if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)) == size) { + switch(raw->header.dwType) + { + case RIM_TYPEKEYBOARD: + keyboard_handle(raw); + break; + case RIM_TYPEMOUSE: + win_mouse_handle(raw); + break; + case RIM_TYPEHID: + win_joystick_handle(raw); + break; + } + } + free(raw); + } + break; + case WM_SETFOCUS: + infocus = 1; +#ifndef NO_KEYBOARD_HOOK + if (! hook_enabled) { + hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, + LowLevelKeyboardProc, + GetModuleHandle(NULL), + 0); + hook_enabled = 1; + } +#endif + break; + + case WM_KILLFOCUS: + infocus = 0; + plat_mouse_capture(0); +#ifndef NO_KEYBOARD_HOOK + if (hook_enabled) { + UnhookWindowsHookEx(hKeyboardHook); + hook_enabled = 0; + } +#endif + break; + + case WM_LBUTTONUP: + pclog("video_fullscreen = %i\n", video_fullscreen); + if (! video_fullscreen) + plat_mouse_capture(1); + break; + + case WM_MBUTTONUP: + if (mouse_get_buttons() < 3) + plat_mouse_capture(0); + break; + + default: + return(1); + /* return(CallWindowProc((WNDPROC)input_orig_proc, + hwnd, message, wParam, lParam)); */ + } + + return(0); +} + + static LRESULT CALLBACK MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -383,6 +462,9 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) int temp_x, temp_y; + if (input_proc(hwnd, message, wParam, lParam) == 0) + return(0); + switch (message) { case WM_CREATE: SetTimer(hwnd, TIMER_1SEC, 1000, NULL); @@ -571,6 +653,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) CheckMenuItem(hmenu, IDM_VID_SCALE_1X+scale, MF_UNCHECKED); scale = LOWORD(wParam) - IDM_VID_SCALE_1X; CheckMenuItem(hmenu, IDM_VID_SCALE_1X+scale, MF_CHECKED); + reset_screen_size(); device_force_redraw(); video_force_resize_set(1); config_save(); @@ -716,11 +799,10 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) GetWindowRect(hwndSBAR, &rect); sbar_height = rect.bottom - rect.top; rect_p = (RECT*)lParam; - if (vid_resize) { + if (vid_resize) MoveWindow(hwnd, rect_p->left, rect_p->top, rect_p->right - rect_p->left, rect_p->bottom - rect_p->top, TRUE); - } else if (!user_resize) { + else if (!user_resize) doresize = 1; - } break; case WM_SIZE: @@ -773,6 +855,9 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } plat_vidapi_enable(1); + plat_vidapi_enable(0); + plat_vidapi_enable(1); + config_save(); break; @@ -939,7 +1024,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_ACTIVATE: - if (wParam != WA_INACTIVE) { + if ((wParam != WA_INACTIVE) && !(video_fullscreen & 2)) { video_force_resize_set(1); plat_vidapi_enable(0); plat_vidapi_enable(1); @@ -966,6 +1051,38 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK SubWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_LBUTTONUP: + if (! video_fullscreen) + plat_mouse_capture(1); + break; + + case WM_MBUTTONUP: + if (mouse_get_buttons() < 3) + plat_mouse_capture(0); + break; + + default: + return(DefWindowProc(hwnd, message, wParam, lParam)); + } + + return(0); +} + + +static LRESULT CALLBACK +SDLMainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (input_proc(hwnd, message, wParam, lParam) == 0) + return(0); + + return(DefWindowProc(hwnd, message, wParam, lParam)); +} + + +static LRESULT CALLBACK +SDLSubWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return(DefWindowProc(hwnd, message, wParam, lParam)); } @@ -1056,6 +1173,14 @@ ui_init(int nCmdShow) return(2); wincl.lpszClassName = SUB_CLASS_NAME; wincl.lpfnWndProc = SubWindowProcedure; + if (! RegisterClassEx(&wincl)) + return(2); + wincl.lpszClassName = SDL_CLASS_NAME; + wincl.lpfnWndProc = SDLMainWindowProcedure; + if (! RegisterClassEx(&wincl)) + return(2); + wincl.lpszClassName = SDL_SUB_CLASS_NAME; + wincl.lpfnWndProc = SDLSubWindowProcedure; if (! RegisterClassEx(&wincl)) return(2); @@ -1128,9 +1253,6 @@ ui_init(int nCmdShow) } keyboard_getkeymap(); - /* Set up the main window for RawInput. */ - plat_set_input(hwndMain); - /* Load the accelerator table */ haccel = LoadAccelerators(hinstance, ACCEL_NAME); if (haccel == NULL) { @@ -1149,7 +1271,7 @@ ui_init(int nCmdShow) ghMutex = CreateMutex(NULL, FALSE, NULL); /* Create the Machine Rendering window. */ - hwndRender = CreateWindow(L"STATIC", NULL, WS_CHILD|SS_BITMAP, + hwndRender = CreateWindow(/*L"STATIC"*/ SUB_CLASS_NAME, NULL, WS_CHILD|SS_BITMAP, 0, 0, 1, 1, hwnd, NULL, hinstance, NULL); MoveWindow(hwndRender, 0, 0, scrnsz_x, scrnsz_y, TRUE); @@ -1241,6 +1363,8 @@ ui_init(int nCmdShow) /* Close down the emulator. */ do_stop(); + UnregisterClass(SDL_SUB_CLASS_NAME, hinstance); + UnregisterClass(SDL_CLASS_NAME, hinstance); UnregisterClass(SUB_CLASS_NAME, hinstance); UnregisterClass(CLASS_NAME, hinstance); @@ -1384,100 +1508,3 @@ plat_mouse_capture(int on) mouse_capture = 0; } } - - -/* Catch WM_INPUT messages for 'current focus' window. */ -static LONG_PTR input_orig_proc; -static HWND input_orig_hwnd = NULL; -#if defined(__amd64__) || defined(__aarch64__) -static LRESULT CALLBACK -#else -static BOOL CALLBACK -#endif -input_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) { - case WM_INPUT: - if (infocus) { - UINT size = 0; - PRAWINPUT raw = NULL; - - /* Here we read the raw input data */ - GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); - raw = (PRAWINPUT)malloc(size); - if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)) == size) { - switch(raw->header.dwType) - { - case RIM_TYPEKEYBOARD: - keyboard_handle(raw); - break; - case RIM_TYPEMOUSE: - win_mouse_handle(raw); - break; - case RIM_TYPEHID: - win_joystick_handle(raw); - break; - } - } - free(raw); - } - break; - case WM_SETFOCUS: - infocus = 1; -#ifndef NO_KEYBOARD_HOOK - if (! hook_enabled) { - hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, - LowLevelKeyboardProc, - GetModuleHandle(NULL), - 0); - hook_enabled = 1; - } -#endif - break; - - case WM_KILLFOCUS: - infocus = 0; - plat_mouse_capture(0); -#ifndef NO_KEYBOARD_HOOK - if (hook_enabled) { - UnhookWindowsHookEx(hKeyboardHook); - hook_enabled = 0; - } -#endif - break; - - case WM_LBUTTONUP: - if (! video_fullscreen) - plat_mouse_capture(1); - break; - - case WM_MBUTTONUP: - if (mouse_get_buttons() < 3) - plat_mouse_capture(0); - break; - - default: - return(CallWindowProc((WNDPROC)input_orig_proc, - hwnd, message, wParam, lParam)); - } - - return(0); -} - - -/* Set up a handler for the 'currently active' window. */ -void -plat_set_input(HWND h) -{ - /* If needed, rest the old one first. */ - if (input_orig_hwnd != NULL) { - SetWindowLongPtr(input_orig_hwnd, GWLP_WNDPROC, - (LONG_PTR)input_orig_proc); - } - - /* Redirect the window procedure so we can catch WM_INPUT. */ - input_orig_proc = GetWindowLongPtr(h, GWLP_WNDPROC); - input_orig_hwnd = h; - SetWindowLongPtr(h, GWLP_WNDPROC, (LONG_PTR)&input_proc); - ImmAssociateContext(h, NULL); -} From 28719fe8712758cc6d16c101cf1c41e7793528b2 Mon Sep 17 00:00:00 2001 From: qeeg Date: Sat, 28 Nov 2020 14:06:20 -0600 Subject: [PATCH 57/67] Be a bit more specific in the bug report issue template --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index c2ca3446f..72fca815d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -25,7 +25,7 @@ If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. Windows 10] - - 86Box version: [e.g. v2.06 build 2007] + - 86Box version: [e.g. v2.06 build 2007, saying "Latest from Jenkins" isn't helpful] - Build type: [i.e. regular, optimized, or dev] **Additional context** From 54c1ea2e3b9f3df864f13feb63f42b6e77e0f638 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sat, 28 Nov 2020 23:52:04 +0100 Subject: [PATCH 58/67] Ported the 128K mapping fixes to 86Box. --- src/video/vid_et4000.c | 9 +++++++++ src/video/vid_et4000w32.c | 2 +- src/video/vid_tvga.c | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index aa1ccf52c..8da66fb7f 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -245,6 +245,15 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) svga->read_bank = ((dev->banking >> 4) & 0x0f) * 0x10000; } else svga->write_bank = svga->read_bank = 0; + + old = svga->gdcreg[6]; + svga_out(addr, val, svga); + if ((old & 0xc) != 0 && (val & 0xc) == 0) + { + /*override mask - ET4000 supports linear 128k at A0000*/ + svga->banked_mask = 0x1ffff; + } + return; } break; diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 9fb13de5b..2c04b454e 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -454,7 +454,7 @@ void et4000w32p_recalcmapping(et4000w32p_t *et4000) case 0x0: case 0x4: case 0x8: case 0xC: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); mem_mapping_disable(&et4000->mmu_mapping); - svga->banked_mask = 0xffff; + svga->banked_mask = 0x1ffff; break; case 0x1: /*64k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index 750144159..b8065457f 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -127,6 +127,15 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) case 0x3CF: switch (svga->gdcaddr & 15) { + case 0x6: + old = svga->gdcreg[6]; + svga_out(addr, val, svga); + if ((old & 0xc) != 0 && (val & 0xc) == 0) + { + /*override mask - TVGA supports linear 128k at A0000*/ + svga->banked_mask = 0x1ffff; + } + return; case 0xE: svga->gdcreg[0xe] = val ^ 2; tvga->tvga_3d9 = svga->gdcreg[0xe] & 0xf; From a1bb128cd9589b4cac37217270e51752e2880cfd Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 29 Nov 2020 00:55:24 +0100 Subject: [PATCH 59/67] Some tweaks to resizing, considerably reduces the stalls. --- src/win/win_sdl.c | 2 +- src/win/win_ui.c | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index 7e29d6381..862927f59 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -543,7 +543,7 @@ sdl_enable(int enable) return; SDL_LockMutex(sdl_mutex); - sdl_enabled = enable; + sdl_enabled = !!enable; if (enable == 1) { SDL_SetWindowSize(sdl_win, cur_ww, cur_wh); diff --git a/src/win/win_ui.c b/src/win/win_ui.c index f4cf7047f..7d9c88164 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -853,10 +853,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) window_h = rect.bottom - rect.top; save_window_pos = 1; } - plat_vidapi_enable(1); - - plat_vidapi_enable(0); - plat_vidapi_enable(1); + plat_vidapi_enable(2); config_save(); break; From a5ae4cfba5de8bd3b3543520d30aa98008b1a73c Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 30 Nov 2020 05:27:04 +0100 Subject: [PATCH 60/67] Got completely rid of readmemb386l() and writememb386l(). --- src/codegen/codegen_x86.c | 40 +++++++++++---------- src/cpu/386_common.c | 4 --- src/cpu/386_common.h | 15 ++++---- src/include/86box/mem.h | 12 ++----- src/mem/mem.c | 75 +++++++++++++++++++++++++++------------ 5 files changed, 83 insertions(+), 63 deletions(-) diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index 8ad2222bd..4ad608aac 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -148,13 +148,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmembl*/ - addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addlong((uint32_t)readmembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -360,13 +361,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememb386l*/ - addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xe8); /*CALL writemembl*/ + addlong((uint32_t)writemembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -575,13 +577,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmembl*/ - addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addlong((uint32_t)readmembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -777,13 +780,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xc3); addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememb386l*/ - addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xe8); /*CALL writemembl*/ + addlong((uint32_t)writemembl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 4f03f0aca..59ae935a1 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -1465,11 +1465,7 @@ checkio(int port) return 1; cpl_override = 1; -#ifdef USE_NEW_DYNAREC d = readmembl(tr.base + t + (port >> 3)); -#else - d = readmemb386l(0, tr.base + t + (port >> 3)); -#endif cpl_override = 0; return d & (1 << (port & 7)); } diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index baf5a63e1..2c7c0eaff 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -32,15 +32,12 @@ #define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 3)) writememll((s)+(a),v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v #define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v #else -#undef readmemb -#undef writememb - - -#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF)?readmemb386l(s,a): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uintptr_t)((s) + (a))) ) +#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uintptr_t)((s) + (a))) ) +#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) #define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a)))) -#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF) writememb386l(s,a,v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v - +#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF) writemembl((s)+(a),v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v #define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v #define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v #define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v @@ -359,7 +356,7 @@ static __inline void seteaq(uint64_t v) #define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v #define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v #else -#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else { writememb386l(easeg,cpu_state.eaaddr,v); } } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v +#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else { writemembl(easeg+cpu_state.eaaddr,v); } } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v #define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else { writememwl(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].w=v #define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else { writememll(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].l=v #endif @@ -369,7 +366,7 @@ static __inline void seteaq(uint64_t v) #define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); #define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); #else -#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v); +#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); #define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); #define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); #endif diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index a5bae6f89..7e7d4a67c 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -236,15 +236,11 @@ extern uint16_t read_mem_w(uint32_t addr); extern void write_mem_b(uint32_t addr, uint8_t val); extern void write_mem_w(uint32_t addr, uint16_t val); -#ifndef USE_NEW_DYNAREC -#define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a))) -#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) -#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) - extern uint8_t readmembl(uint32_t addr); extern void writemembl(uint32_t addr, uint8_t val); -extern uint8_t readmemb386l(uint32_t seg, uint32_t addr); -extern void writememb386l(uint32_t seg, uint32_t addr, uint8_t val); +extern void rwmembl(uint32_t raddr, uint32_t waddr, uint8_t val); + +#ifndef USE_NEW_DYNAREC extern uint16_t readmemwl(uint32_t seg, uint32_t addr); extern void writememwl(uint32_t seg, uint32_t addr, uint16_t val); extern uint32_t readmemll(uint32_t seg, uint32_t addr); @@ -252,8 +248,6 @@ extern void writememll(uint32_t seg, uint32_t addr, uint32_t val); extern uint64_t readmemql(uint32_t seg, uint32_t addr); extern void writememql(uint32_t seg, uint32_t addr, uint64_t val); #else -extern uint8_t readmembl(uint32_t addr); -extern void writemembl(uint32_t addr, uint8_t val); extern uint16_t readmemwl(uint32_t addr); extern void writememwl(uint32_t addr, uint16_t val); extern uint32_t readmemll(uint32_t addr); diff --git a/src/mem/mem.c b/src/mem/mem.c index 52fae564d..0f281cf02 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -804,6 +804,55 @@ writemembl(uint32_t addr, uint8_t val) } +void +rwmembl(uint32_t raddr, uint32_t waddr, uint8_t val) +{ + uint64_t raddr64 = (uint64_t) raddr; + uint64_t waddr64 = (uint64_t) waddr; + mem_mapping_t *rmap, *wmap; + uint8_t temp = 0xff; + + mem_logical_addr = raddr; + + if (cr0 >> 31) { + raddr64 = mmutranslate_read(raddr); + if (raddr64 == 0xffffffffffffffffULL) + goto do_writebl; + if (raddr64 > 0xffffffffULL) + goto do_writebl; + } + raddr = (uint32_t) (raddr64 & rammask); + + rmap = read_mapping[raddr >> MEM_GRANULARITY_BITS]; + if (rmap && rmap->read_b) + temp = rmap->read_b(raddr, rmap->p); + +do_writebl: + if (cpu_state.abrt) + return; + + mem_logical_addr = waddr; + + if (page_lookup[waddr >> 12] && page_lookup[waddr >> 12]->write_b) { + page_lookup[waddr >> 12]->write_b(waddr, temp, page_lookup[waddr >> 12]); + return; + } + + if (cr0 >> 31) { + waddr64 = mmutranslate_write(waddr); + if (waddr64 == 0xffffffffffffffffULL) + return; + if (waddr64 > 0xffffffffULL) + return; + } + waddr = (uint32_t) (waddr64 & rammask); + + wmap = write_mapping[waddr >> MEM_GRANULARITY_BITS]; + if (wmap && wmap->write_b) + wmap->write_b(waddr, temp, wmap->p); +} + + #ifdef USE_NEW_DYNAREC uint16_t readmemwl(uint32_t addr) @@ -1112,20 +1161,6 @@ writememql(uint32_t addr, uint64_t val) } } #else -uint8_t -readmemb386l(uint32_t seg, uint32_t addr) -{ - return readmembl(addr + seg); -} - - -void -writememb386l(uint32_t seg, uint32_t addr, uint8_t val) -{ - writemembl(addr + seg, val); -} - - uint16_t readmemwl(uint32_t seg, uint32_t addr) { @@ -1143,8 +1178,7 @@ readmemwl(uint32_t seg, uint32_t addr) if (mmutranslate_read(addr2+1) == 0xffffffffffffffffULL) return 0xffff; } - if (is386) return readmemb386l(seg,addr)|(((uint16_t) readmemb386l(seg,addr+1))<<8); - else return readmembl(seg+addr)|(((uint16_t) readmembl(seg+addr+1))<<8); + return readmembl(seg+addr)|(((uint16_t) readmembl(seg+addr+1))<<8); } else if (readlookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); } @@ -1193,13 +1227,8 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; if (mmutranslate_write(addr2+1) == 0xffffffffffffffffULL) return; } - if (is386) { - writememb386l(seg,addr,val); - writememb386l(seg,addr+1,val>>8); - } else { - writemembl(seg+addr,val); - writemembl(seg+addr+1,val>>8); - } + writemembl(seg+addr,val); + writemembl(seg+addr+1,val>>8); return; } else if (writelookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) { *(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val; From f7dcd358f0cb1127c323aee0e279fd3630a30cb6 Mon Sep 17 00:00:00 2001 From: qeeg Date: Mon, 30 Nov 2020 02:27:36 -0600 Subject: [PATCH 61/67] i386 CPUs don't have the WP bit in CR0. Fixes IBM AIX 1.3 --- src/mem/mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mem/mem.c b/src/mem/mem.c index 0f281cf02..f416171a6 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -296,7 +296,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) if ((temp & 0x80) && (cr4 & CR4_PSE)) { /*4MB page*/ - if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { + if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (!is386 && (cr0 & WP_FLAG))))) { cr2 = addr; temp &= 1; if (CPL == 3) @@ -317,7 +317,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); temp3 = temp & temp2; - if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { + if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (!is386 && (cr0 & WP_FLAG))))) { cr2 = addr; temp &= 1; if (CPL == 3) temp |= 4; From 1ddee67aa660da08c57281c1e027a0f7e766970e Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 1 Dec 2020 02:41:22 +0100 Subject: [PATCH 62/67] Got rid of the last differences between the old and new recompilers with regards to the readmem*/writemem* functions. --- src/codegen/codegen_ops_x86-64.h | 70 +++++++++++++++++++------------- src/codegen/codegen_x86.c | 70 ++++++++++++++++++-------------- src/cpu/386_common.h | 60 ++++----------------------- src/include/86box/mem.h | 9 ---- src/mem/mem.c | 56 ++++++++++++------------- 5 files changed, 116 insertions(+), 149 deletions(-) diff --git a/src/codegen/codegen_ops_x86-64.h b/src/codegen/codegen_ops_x86-64.h index ab68a535a..452f09937 100644 --- a/src/codegen/codegen_ops_x86-64.h +++ b/src/codegen/codegen_ops_x86-64.h @@ -1026,9 +1026,10 @@ static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemb386l); + call_long((uintptr_t)readmembl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -1105,8 +1106,9 @@ static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemwl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1190,8 +1192,9 @@ static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemll); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1269,8 +1272,9 @@ static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemql); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1394,10 +1398,11 @@ static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - load_param_3_reg_32(host_reg); - call_long((uintptr_t)writememb386l); + load_param_2_reg_32(host_reg); + call_long((uintptr_t)writemembl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -1485,9 +1490,10 @@ static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - load_param_3_reg_32(host_reg); + load_param_2_reg_32(host_reg); call_long((uintptr_t)writememwl); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1574,9 +1580,10 @@ static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - load_param_3_reg_32(host_reg); + load_param_2_reg_32(host_reg); call_long((uintptr_t)writememll); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -1664,9 +1671,10 @@ static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12+4+6); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - load_param_3_reg_64(host_reg); + load_param_2_reg_64(host_reg); call_long((uintptr_t)writememql); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -5763,9 +5771,10 @@ static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemb386l); + call_long((uintptr_t)readmembl); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); /*done:*/ @@ -5841,8 +5850,9 @@ static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemwl); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); @@ -5918,8 +5928,9 @@ static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+12); /*slowpath:*/ + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); call_long((uintptr_t)readmemll); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); @@ -6023,10 +6034,11 @@ static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12); /*slowpath:*/ - load_param_3_reg_32(host_reg); - load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)writememb386l); + load_param_2_reg_32(host_reg); + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); + load_param_1_reg_32(REG_ECX); + call_long((uintptr_t)writemembl); /*done:*/ } static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) @@ -6107,9 +6119,10 @@ static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12); /*slowpath:*/ - load_param_3_reg_32(host_reg); - load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); + load_param_2_reg_32(host_reg); + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); + load_param_1_reg_32(REG_ECX); call_long((uintptr_t)writememwl); /*done:*/ } @@ -6189,9 +6202,10 @@ static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) addbyte(0xeb); /*JMP done*/ addbyte(2+2+3+12); /*slowpath:*/ - load_param_3_reg_32(host_reg); - load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); + load_param_2_reg_32(host_reg); + addbyte(0x01); /*ADD ECX,EAX*/ + addbyte(0xc1); + load_param_1_reg_32(REG_ECX); call_long((uintptr_t)writememll); /*done:*/ } diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index 4ad608aac..31b3202e6 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -204,13 +204,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemwl*/ addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -258,13 +259,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemll*/ addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -313,13 +315,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_Q() addbyte(4); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemql*/ addlong((uint32_t)readmemql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -416,13 +419,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ addbyte(0xe8); /*CALL writememwl*/ addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -469,13 +473,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ addbyte(0xe8); /*CALL writememll*/ addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -527,13 +532,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_Q() addbyte(0x51); /*slowpath: PUSH ECX*/ addbyte(0x53); /*PUSH EBX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EDX,EAX*/ + addbyte(0xC2); addbyte(0x52); /*PUSH EDX*/ addbyte(0xe8); /*CALL writememql*/ addlong((uint32_t)writememql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 16*/ + addbyte(0x83); /*ADD ESP, 12*/ addbyte(0xc4); - addbyte(16); + addbyte(12); addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); addbyte((uint8_t)cpu_state_offset(abrt)); @@ -647,13 +653,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_W_NO_ABRT() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemwl*/ addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -715,13 +722,14 @@ static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT() addbyte(0x3a); addbyte(0xc3); /*RET*/ - addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x01); /*slowpath: ADD ESI,EAX*/ + addbyte(0xc6); addbyte(0x56); /*PUSH ESI*/ addbyte(0xe8); /*CALL readmemll*/ addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0x83); /*ADD ESP, 4*/ addbyte(0xc4); - addbyte(8); + addbyte(4); addbyte(0x89); /*MOV ECX, EAX*/ addbyte(0xc1); #ifndef RELEASE_BUILD @@ -847,13 +855,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ addbyte(0xe8); /*CALL writememwl*/ addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); @@ -912,13 +921,14 @@ static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT() addbyte(0xc3); /*RET*/ addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ + addbyte(0x01); /*ADD EBX,EAX*/ + addbyte(0xC3); addbyte(0x53); /*PUSH EBX*/ addbyte(0xe8); /*CALL writememll*/ addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0x83); /*ADD ESP, 8*/ addbyte(0xc4); - addbyte(12); + addbyte(8); #ifndef RELEASE_BUILD addbyte(0x80); /*CMP abrt, 0*/ addbyte(0x7d); diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index 2c7c0eaff..ed4bc84d7 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -21,47 +21,20 @@ #include -#ifdef USE_NEW_DYNAREC -#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uintptr_t)((s) + (a)))) -#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 1))?readmemwl((s)+(a)):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a)))) -#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 3))?readmemll((s)+(a)):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a)))) -#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 7))?readmemql((s)+(a)):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a)))) - -#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV) writemembl((s)+(a),v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v -#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 1)) writememwl((s)+(a),v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v -#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 3)) writememll((s)+(a),v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v -#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (((s)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v -#else #define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uintptr_t)((s) + (a))) ) -#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) -#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) -#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a)))) +#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl((s)+(a)):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll((s)+(a)):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql((s)+(a)):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uintptr_t)((s)+(a)))) #define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF) writemembl((s)+(a),v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v -#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v -#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v -#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v -#endif +#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl((s)+(a),v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v +#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll((s)+(a),v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v +#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==LOOKUP_INV || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uintptr_t)((s) + (a))) = v int checkio(int port); -#ifdef USE_NEW_DYNAREC -#define check_io_perm(port) if (!IOPLp || (cpu_state.eflags&VM_FLAG)) \ - { \ - int tempi = checkio(port); \ - if (cpu_state.abrt) return 1; \ - if (tempi) \ - { \ - if (cpu_state.eflags & VM_FLAG) \ - x86gpf_expected(NULL,0); \ - else \ - x86gpf(NULL,0); \ - return 1; \ - } \ - } -#else #define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (cpu_state.eflags&VM_FLAG))) \ { \ int tempi = checkio(port); \ @@ -75,7 +48,6 @@ int checkio(int port); return 1; \ } \ } -#endif #define SEG_CHECK_READ(seg) \ do \ @@ -344,32 +316,16 @@ static __inline void seteaq(uint64_t v) { if (seteaq_cwc()) return; -#ifdef USE_NEW_DYNAREC writememql(easeg + cpu_state.eaaddr, v); -#else - writememql(easeg, cpu_state.eaaddr, v); -#endif } -#ifdef USE_NEW_DYNAREC #define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v -#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v -#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v -#else -#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else { writemembl(easeg+cpu_state.eaaddr,v); } } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v -#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else { writememwl(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].w=v -#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else { writememll(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].l=v -#endif +#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v +#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE_COMMON(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v -#ifdef USE_NEW_DYNAREC #define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); #define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); #define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); -#else -#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); -#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); -#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); -#endif #define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ #define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 diff --git a/src/include/86box/mem.h b/src/include/86box/mem.h index 7e7d4a67c..b6718762b 100644 --- a/src/include/86box/mem.h +++ b/src/include/86box/mem.h @@ -240,21 +240,12 @@ extern uint8_t readmembl(uint32_t addr); extern void writemembl(uint32_t addr, uint8_t val); extern void rwmembl(uint32_t raddr, uint32_t waddr, uint8_t val); -#ifndef USE_NEW_DYNAREC -extern uint16_t readmemwl(uint32_t seg, uint32_t addr); -extern void writememwl(uint32_t seg, uint32_t addr, uint16_t val); -extern uint32_t readmemll(uint32_t seg, uint32_t addr); -extern void writememll(uint32_t seg, uint32_t addr, uint32_t val); -extern uint64_t readmemql(uint32_t seg, uint32_t addr); -extern void writememql(uint32_t seg, uint32_t addr, uint64_t val); -#else extern uint16_t readmemwl(uint32_t addr); extern void writememwl(uint32_t addr, uint16_t val); extern uint32_t readmemll(uint32_t addr); extern void writememll(uint32_t addr, uint32_t val); extern uint64_t readmemql(uint32_t addr); extern void writememql(uint32_t addr, uint64_t val); -#endif extern uint8_t *getpccache(uint32_t a); extern uint64_t mmutranslatereal(uint32_t addr, int rw); diff --git a/src/mem/mem.c b/src/mem/mem.c index f416171a6..a448dc1c7 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -296,7 +296,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) if ((temp & 0x80) && (cr4 & CR4_PSE)) { /*4MB page*/ - if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (!is386 && (cr0 & WP_FLAG))))) { + if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { cr2 = addr; temp &= 1; if (CPL == 3) @@ -317,7 +317,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); temp3 = temp & temp2; - if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (!is386 && (cr0 & WP_FLAG))))) { + if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { cr2 = addr; temp &= 1; if (CPL == 3) temp |= 4; @@ -1162,11 +1162,11 @@ writememql(uint32_t addr, uint64_t val) } #else uint16_t -readmemwl(uint32_t seg, uint32_t addr) +readmemwl(uint32_t addr) { uint64_t addr64 = (uint64_t) addr; mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; + uint32_t addr2 = mem_logical_addr = addr; if (addr2 & 1) { if (!cpu_cyrix_alignment || (addr2 & 7) == 7) @@ -1178,7 +1178,7 @@ readmemwl(uint32_t seg, uint32_t addr) if (mmutranslate_read(addr2+1) == 0xffffffffffffffffULL) return 0xffff; } - return readmembl(seg+addr)|(((uint16_t) readmembl(seg+addr+1))<<8); + return readmembl(addr)|(((uint16_t) readmembl(addr+1))<<8); } else if (readlookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); } @@ -1200,12 +1200,8 @@ readmemwl(uint32_t seg, uint32_t addr) return map->read_w(addr2, map->p); if (map && map->read_b) { - if (AT) - return map->read_b(addr2, map->p) | - ((uint16_t) (map->read_b(addr2 + 1, map->p)) << 8); - else - return map->read_b(addr2, map->p) | - ((uint16_t) (map->read_b(seg + ((addr + 1) & 0xffff), map->p)) << 8); + return map->read_b(addr2, map->p) | + ((uint16_t) (map->read_b(addr2 + 1, map->p)) << 8); } return 0xffff; @@ -1213,11 +1209,11 @@ readmemwl(uint32_t seg, uint32_t addr) void -writememwl(uint32_t seg, uint32_t addr, uint16_t val) +writememwl(uint32_t addr, uint16_t val) { uint64_t addr64 = (uint64_t) addr; mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; + uint32_t addr2 = mem_logical_addr = addr; if (addr2 & 1) { if (!cpu_cyrix_alignment || (addr2 & 7) == 7) @@ -1227,8 +1223,8 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; if (mmutranslate_write(addr2+1) == 0xffffffffffffffffULL) return; } - writemembl(seg+addr,val); - writemembl(seg+addr+1,val>>8); + writemembl(addr,val); + writemembl(addr+1,val>>8); return; } else if (writelookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) { *(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val; @@ -1268,11 +1264,11 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) uint32_t -readmemll(uint32_t seg, uint32_t addr) +readmemll(uint32_t addr) { uint64_t addr64 = (uint64_t) addr; mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; + uint32_t addr2 = mem_logical_addr = addr; if (addr2 & 3) { if (!cpu_cyrix_alignment || (addr2 & 7) > 4) @@ -1282,7 +1278,7 @@ readmemll(uint32_t seg, uint32_t addr) if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) return 0xffffffff; if (mmutranslate_read(addr2+3) == 0xffffffffffffffffULL) return 0xffffffff; } - return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); + return readmemwl(addr)|(readmemwl(addr+2)<<16); } else if (readlookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2); } @@ -1318,11 +1314,11 @@ readmemll(uint32_t seg, uint32_t addr) void -writememll(uint32_t seg, uint32_t addr, uint32_t val) +writememll(uint32_t addr, uint32_t val) { uint64_t addr64 = (uint64_t) addr; mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; + uint32_t addr2 = mem_logical_addr = addr; if (addr2 & 3) { if (!cpu_cyrix_alignment || (addr2 & 7) > 4) @@ -1332,8 +1328,8 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; if (mmutranslate_write(addr2+3) == 0xffffffffffffffffULL) return; } - writememwl(seg,addr,val); - writememwl(seg,addr+2,val>>16); + writememwl(addr,val); + writememwl(addr+2,val>>16); return; } else if (writelookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) { *(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val; @@ -1379,11 +1375,11 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) uint64_t -readmemql(uint32_t seg, uint32_t addr) +readmemql(uint32_t addr) { uint64_t addr64 = (uint64_t) addr; mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; + uint32_t addr2 = mem_logical_addr = addr; if (addr2 & 7) { cycles -= timing_misaligned; @@ -1392,7 +1388,7 @@ readmemql(uint32_t seg, uint32_t addr) if (mmutranslate_read(addr2) == 0xffffffffffffffffULL) return 0xffffffffffffffffULL; if (mmutranslate_read(addr2+7) == 0xffffffffffffffffULL) return 0xffffffffffffffffULL; } - return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); + return readmemll(addr)|((uint64_t)readmemll(addr+4)<<32); } else if (readlookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2); } @@ -1412,16 +1408,16 @@ readmemql(uint32_t seg, uint32_t addr) if (map && map->read_l) return map->read_l(addr2, map->p) | ((uint64_t)map->read_l(addr2 + 4, map->p) << 32); - return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); + return readmemll(addr) | ((uint64_t)readmemll(addr+4)<<32); } void -writememql(uint32_t seg, uint32_t addr, uint64_t val) +writememql(uint32_t addr, uint64_t val) { uint64_t addr64 = (uint64_t) addr; mem_mapping_t *map; - uint32_t addr2 = mem_logical_addr = seg + addr; + uint32_t addr2 = mem_logical_addr = addr; if (addr2 & 7) { cycles -= timing_misaligned; @@ -1430,8 +1426,8 @@ writememql(uint32_t seg, uint32_t addr, uint64_t val) if (mmutranslate_write(addr2) == 0xffffffffffffffffULL) return; if (mmutranslate_write(addr2+7) == 0xffffffffffffffffULL) return; } - writememll(seg, addr, val); - writememll(seg, addr+4, val >> 32); + writememll(addr, val); + writememll(addr+4, val >> 32); return; } else if (writelookup2[addr2 >> 12] != (uintptr_t) LOOKUP_INV) { *(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val; From 62dc0b01546b8199061e5031518607641e6766ef Mon Sep 17 00:00:00 2001 From: qeeg Date: Mon, 30 Nov 2020 20:09:13 -0600 Subject: [PATCH 63/67] Readd the AIX fix --- src/mem/mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mem/mem.c b/src/mem/mem.c index a448dc1c7..7c8f0228a 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -296,7 +296,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) if ((temp & 0x80) && (cr4 & CR4_PSE)) { /*4MB page*/ - if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { + if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (!is386 && (cr0 & WP_FLAG))))) { cr2 = addr; temp &= 1; if (CPL == 3) @@ -317,7 +317,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); temp3 = temp & temp2; - if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (cr0 & WP_FLAG)))) { + if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (!is386 && (cr0 & WP_FLAG))))) { cr2 = addr; temp &= 1; if (CPL == 3) temp |= 4; From c5f4cda6db6a0874cabab3e760abfeeb7ba979a8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 1 Dec 2020 05:05:44 +0100 Subject: [PATCH 64/67] Fixed the AIX fix. --- src/mem/mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mem/mem.c b/src/mem/mem.c index 7c8f0228a..7a7b8c51a 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -296,7 +296,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) if ((temp & 0x80) && (cr4 & CR4_PSE)) { /*4MB page*/ - if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (!is386 && (cr0 & WP_FLAG))))) { + if (((CPL == 3) && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (((CPL == 3) && !cpl_override) || (is486 && (cr0 & WP_FLAG))))) { cr2 = addr; temp &= 1; if (CPL == 3) @@ -317,7 +317,7 @@ mmutranslatereal_normal(uint32_t addr, int rw) temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); temp3 = temp & temp2; - if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (!is386 && (cr0 & WP_FLAG))))) { + if (!(temp&1) || ((CPL == 3) && !(temp3 & 4) && !cpl_override) || (rw && !(temp3 & 2) && (((CPL == 3) && !cpl_override) || (is486 && (cr0 & WP_FLAG))))) { cr2 = addr; temp &= 1; if (CPL == 3) temp |= 4; From 462ff300dab267808d95b68d5c756e0076ada87e Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 1 Dec 2020 21:06:01 +0100 Subject: [PATCH 65/67] Ported the most important patches from PCem. --- src/cpu/386_common.c | 4 +++ src/video/vid_voodoo_banshee.c | 41 ++++++++++++++++++++++---- src/video/vid_voodoo_banshee_blitter.c | 25 ++++++++++++---- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 59ae935a1..062926e0a 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -1169,6 +1169,8 @@ enter_smm(int in_hlt) flushmmucache(); } + + oldcpl = 0; cpu_cur_status &= ~(CPU_STATUS_PMODE | CPU_STATUS_V86); CPU_BLOCK_END(); @@ -1265,6 +1267,8 @@ leave_smm(void) nmi_mask = 1; + oldcpl = CPL; + CPU_BLOCK_END(); x386_common_log("CS : seg = %04X, base = %08X, limit = %08X, limit_low = %08X, limit_high = %08X, access = %02X, ar_high = %02X\n", diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 2be43715c..2d3a378d5 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -2357,11 +2357,11 @@ static uint8_t banshee_pci_read(int func, int addr, void *p) case 0x1a: ret = 0x00; break; case 0x1b: ret = 0x00; break; - /*Undocumented, but Voodoo 3 BIOS checks this*/ - case 0x2c: ret = 0x1a; break; - case 0x2d: ret = 0x12; break; - case 0x2e: ret = (banshee->type == TYPE_V3_3000) ? 0x3a : 0x30; break; - case 0x2f: ret = 0x00; break; + /*Subsystem vendor ID*/ + case 0x2c: ret = banshee->pci_regs[0x2c]; break; + case 0x2d: ret = banshee->pci_regs[0x2d]; break; + case 0x2e: ret = banshee->pci_regs[0x2e]; break; + case 0x2f: ret = banshee->pci_regs[0x2f]; break; case 0x30: ret = banshee->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ case 0x31: ret = 0x00; break; @@ -2667,6 +2667,37 @@ static void *banshee_init_common(const device_t *info, wchar_t *fn, int has_sgra banshee->i2c_ddc = i2c_gpio_init("ddc_voodoo_banshee"); banshee->ddc = ddc_init(i2c_gpio_get_bus(banshee->i2c_ddc)); + switch (type) + { + case TYPE_BANSHEE: + if (has_sgram) { + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x04; + banshee->pci_regs[0x2f] = 0x00; + } else { + banshee->pci_regs[0x2c] = 0x02; + banshee->pci_regs[0x2d] = 0x11; + banshee->pci_regs[0x2e] = 0x17; + banshee->pci_regs[0x2f] = 0x10; + } + break; + + case TYPE_V3_2000: + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x30; + banshee->pci_regs[0x2f] = 0x00; + break; + + case TYPE_V3_3000: + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x3a; + banshee->pci_regs[0x2f] = 0x00; + break; + } + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_banshee); return banshee; diff --git a/src/video/vid_voodoo_banshee_blitter.c b/src/video/vid_voodoo_banshee_blitter.c index d86ff8eb9..13ed8edbd 100644 --- a/src/video/vid_voodoo_banshee_blitter.c +++ b/src/video/vid_voodoo_banshee_blitter.c @@ -918,7 +918,7 @@ static void step_line(voodoo_t *voodoo) } -static void banshee_do_line(voodoo_t *voodoo) +static void banshee_do_line(voodoo_t *voodoo, int draw_last_pixel) { clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; uint8_t rop = voodoo->banshee_blt.command >> 24; @@ -975,6 +975,15 @@ static void banshee_do_line(voodoo_t *voodoo) } } + if (draw_last_pixel) + { + int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); + int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; + + if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); + } + voodoo->banshee_blt.srcXY = (x & 0xffff) | (y << 16); voodoo->banshee_blt.srcX = x; voodoo->banshee_blt.srcY = y; @@ -1112,8 +1121,12 @@ static void banshee_do_2d_blit(voodoo_t *voodoo, int count, uint32_t data) banshee_do_rectfill(voodoo); break; + case COMMAND_CMD_LINE: + banshee_do_line(voodoo, 1); + break; + case COMMAND_CMD_POLYLINE: - banshee_do_line(voodoo); + banshee_do_line(voodoo, 0); break; default: @@ -1386,18 +1399,18 @@ void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) banshee_do_rectfill(voodoo); break; -/* case COMMAND_CMD_LINE: + case COMMAND_CMD_LINE: voodoo->banshee_blt.dstXY = val; voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; - banshee_do_line(voodoo); - break;*/ + banshee_do_line(voodoo, 1); + break; case COMMAND_CMD_POLYLINE: voodoo->banshee_blt.dstXY = val; voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; - banshee_do_line(voodoo); + banshee_do_line(voodoo, 0); break; case COMMAND_CMD_POLYFILL: From 1bc5eca8fdb144f36dcceec3982f2b8a12d32865 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 2 Dec 2020 05:52:28 +0100 Subject: [PATCH 66/67] 808x PIC acknowledges now incur bus access wait states. --- src/cpu/808x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 72a66703f..bb579f473 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1207,9 +1207,11 @@ check_interrupts(void) wait(3, 0); /* ACK to PIC */ temp = pic_irq_ack(); + wait(4, 1); wait(1, 0); /* ACK to PIC */ temp = pic_irq_ack(); + wait(4, 1); wait(1, 0); in_lock = 0; clear_lock = 0; From 8832f9d0e9553f5c9ee01488f3b48dbc22420ff2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 2 Dec 2020 06:11:27 +0100 Subject: [PATCH 67/67] Returning from full screen to resizable window now forces a direct window resize, closes #1129. --- src/include/86box/win.h | 2 ++ src/win/win.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/include/86box/win.h b/src/include/86box/win.h index ceb06f1ba..dd83af427 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -102,6 +102,7 @@ extern HANDLE ghMutex; extern LCID lang_id; extern HICON hIcon[256]; extern RECT oldclip; +extern int sbar_height; // extern int status_is_open; @@ -111,6 +112,7 @@ extern WCHAR wopenfilestring[512]; extern uint8_t filterindex; +extern void ResizeWindowByClientArea(HWND hwnd, int width, int height); extern void InitCrashDump(void); extern HICON LoadIconEx(PCTSTR pszIconName); diff --git a/src/win/win.c b/src/win/win.c index 50c87d015..5322d6c55 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -21,6 +21,7 @@ #define UNICODE #define NTDDI_VERSION 0x06010000 #include +#include #include #include #include @@ -784,6 +785,10 @@ get_vidpause(void) void plat_setfullscreen(int on) { + RECT rect; + int temp_x, temp_y; + int dpi = win_get_dpi(hwndMain); + /* Are we changing from the same state to the same state? */ if ((!!on) == (!!video_fullscreen)) return; @@ -805,8 +810,34 @@ plat_setfullscreen(int on) video_fullscreen = on | 2; if (vid_apis[vid_api].set_fs) vid_apis[vid_api].set_fs(on); - if (!on) + if (!on) { plat_resize(scrnsz_x, scrnsz_y); + if (vid_resize) { + /* scale the screen base on DPI */ + if (dpi_scale) { + temp_x = MulDiv(unscaled_size_x, dpi, 96); + temp_y = MulDiv(unscaled_size_y, dpi, 96); + } else { + temp_x = unscaled_size_x; + temp_y = unscaled_size_y; + } + /* Main Window. */ + ResizeWindowByClientArea(hwndMain, temp_x, temp_y + sbar_height); + + /* Render window. */ + MoveWindow(hwndRender, 0, 0, temp_x, temp_y, TRUE); + GetWindowRect(hwndRender, &rect); + + /* Status bar. */ + MoveWindow(hwndSBAR, 0, rect.bottom, temp_x, 17, TRUE); + + if (mouse_capture) + ClipCursor(&rect); + + scrnsz_x = unscaled_size_x; + scrnsz_y = unscaled_size_y; + } + } video_fullscreen &= 1; video_force_resize_set(1); if (!on)