├── .gitignore ├── CHANGELOG ├── LICENSE ├── README.md ├── bochs-debug-cmds ├── cc ├── .gitignore ├── a20.lisp ├── abi.lisp ├── address.asm ├── arith.asm ├── bga.lisp ├── bitmap.lisp ├── bochs.lisp ├── bootloader.lisp ├── cc.asd ├── config.lisp ├── kernel.lisp ├── keyboard.lisp ├── lap.lisp ├── lnasdf ├── memory.lisp ├── misc.asm ├── nasm.lisp ├── package.lisp ├── paging.lisp ├── test-cc.lisp ├── test.lisp ├── unit-test.lisp ├── util.lisp ├── vga-text.lisp └── x86-64-syntax.lisp ├── debug-qemu ├── debug-virtualbox ├── doc ├── AssemblyX64.md ├── AssemblyX64A.md ├── AssemblyX64Arith.md ├── AssemblyX64B.md ├── AssemblyX64Bit.md ├── AssemblyX64C.md ├── AssemblyX64D.md ├── AssemblyX64E.md ├── AssemblyX64F.md ├── AssemblyX64H.md ├── AssemblyX64I.md ├── AssemblyX64J.md ├── AssemblyX64L.md ├── AssemblyX64M.md ├── AssemblyX64N.md ├── AssemblyX64O.md ├── AssemblyX64P.md ├── AssemblyX64R.md ├── AssemblyX64S.md ├── AssemblyX64T.md ├── AssemblyX64U.md ├── AssemblyX64V.md ├── AssemblyX64W.md ├── AssemblyX64X.md └── CrossCompilation.md ├── run-bochs ├── run-qemu ├── run-virtualbox ├── scripts └── build-bochs └── write-kernel-sbcl /.gitignore: -------------------------------------------------------------------------------- 1 | *.img 2 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Changelog of yalo 2 | 3 | v0.0.1 4 | - Initial release. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yalo 2 | ==== 3 | 4 | # Target 5 | 6 | Yalo is a Lisp OS running on bare metal x86-64 hardware. The system 7 | programming language is **Ink**, a new Lisp dialect which combines the 8 | elegance of Scheme and powerfulness of Common Lisp. The project webpage 9 | is: 10 | 11 | # Status 12 | 13 | The project is only at very very initial stage, with an 14 | [assembler](https://github.com/whily/yalo/blob/master/doc/AssemblyX64.md) 15 | written in Common Lisp, and a 64 bit bootloader. 16 | 17 | "Short term" plan: 18 | 19 | - [x] VGA text mode without using BIOS. 20 | - [x] Keyboard handling without using BIOS. 21 | - [x] Switch to 32 bit protected mode. 22 | - [x] Switch to 64 bit long mode. 23 | - [ ] Physical/virtual memory management. 24 | - [ ] Userland and system call. 25 | - [ ] Implement Ink interpreter with assembly. 26 | - [ ] Self hosting a more powerful Ink interpreter with Ink itself. 27 | 28 | # Getting Started 29 | 30 | ## Getting Bootable Image 31 | 32 | Currently, cross compilation is needed to build one floppy image 33 | containing yalo. 34 | 35 | ### [Cross compilation](https://github.com/whily/yalo/blob/master/doc/CrossCompilation.md) 36 | 37 | Although yalo should compile on any Ansi Common Lisp implementation, 38 | it is only tested on SBCL and Clozure CL (aka CCL). 39 | 40 | Mandatory Requirements: 41 | * [SBCL](http://sbcl.sourceforge.net SBCL) or [CCL](https://ccl.clozure.com/) 42 | * git 43 | 44 | Optional Requirements: 45 | * Emacs 46 | * SLIME 47 | 48 | #### Getting Source Code 49 | 50 | Run following command to anonymously checkout the latest source code 51 | of yalo. 52 | 53 | ```shell 54 | $ git clone https://github.com/whily/yalo.git 55 | ``` 56 | 57 | #### Setup link for ASDF 58 | 59 | Run following commands to make SBCL/CCL aware of the ASDF file for the 60 | cross compiler. Note that one only needs to run the script once. 61 | 62 | ```shell 63 | $ cd yalo/cc 64 | $ ./lnasdf 65 | ``` 66 | 67 | #### Build Floppy Image 68 | 69 | ##### With SBCL or CCL alone 70 | 71 | For SBCL, in the root directory of the project (e.g. directory 72 | `yalo`), run script `write-kernel-sbcl`. Afterwards,`floppy.img` is 73 | written directly to the same directory, where scripts to run the image 74 | (e.g. `run-bochs`) are located. It should be noted that it is assumed 75 | that `sbcl` executable is installed in directory `/usr/bin`. Otherwise 76 | modify script `write-kernel-sbcl` accordingly. 77 | 78 | For CCL, in the root directory of the project, type the following at 79 | REPL to generate `floppy.img`: 80 | 81 | ```lisp 82 | (require 'asdf) 83 | (asdf:oos 'asdf:load-op 'cc) 84 | (in-package :cc) 85 | (write-kernel "../floppy.img") 86 | ``` 87 | 88 | One may type `(ccl:quit)` to exit from CCL. 89 | 90 | ##### With Emacs+SLIME 91 | 92 | Inside Emacs, 93 | 94 | 1. First type `M-x slime` if SLIME is not started. 95 | 2. Type `M-x slime-load-system` then type `cc` when prompted for the 96 | system. 97 | 3. At REPL, type `(in-package :cc)` to switch to package *cc* 98 | (alternatively, one can user keyboard shortcut `C-x M-p` and then type `cc`). 99 | 4. Type `(write-kernel "../floppy.img")` at SLIME REPL to generate the kernel. 100 | Here we assume that current directory is `cc` of the source tree, therefore 101 | `floppy.img` is written directly to the source tree, where scripts to run the 102 | image (e.g. `run-bochs`) are located. 103 | 104 | Above is applicable for both SBCL and CCL, assuming SLIME is 105 | configured properly for the CL implementation(s). 106 | 107 | ## Run Image 108 | 109 | There are various ways to run the image. 110 | 111 | ### Bochs 112 | 113 | Go to the root directory of the source code, where script `run-bochs` 114 | is located. Run the scripts and select *6* to proceed emulation. After 115 | invoking `run-bochs`, select *6*, emulation starts directly. 116 | 117 | On HiDPI screens, the font of Bochs is too small to see. Therefore in 118 | script `run-bochs`, there is one line related 119 | to using SDL2 (make sure the library is installed) as display library 120 | and starts the emulator in fullscreen mode, as below: 121 | 122 | ``` 123 | 'display_library: sdl2, options="fullscreen,gui_debug"' 124 | ``` 125 | 126 | Bochs header bar is not visible in full screen mode. Therefore one 127 | needs to press `Ctrl+Alt+q` to shutdown Yalo to quit emulator. 128 | Alternatively, one can modify the script files (e.g. removing 129 | `fullscreen` option or deleting the line containing `display_library` 130 | completely). 131 | 132 | In addition, `scripts/build-boch` is the script the author used to 133 | compile a customized Bochs. 134 | 135 | Note that on Ubuntu (at least in 16.10), package `bochs-x` should be 136 | installed in addition to package `bochs`. 137 | 138 | ### QEMU 139 | 140 | Similar to Bochs, go to the root directory of the source code, where 141 | script `run-qemu` and `debug-qemu` are located. 142 | 143 | In both `run-qemu` and `debug-qemu`, QEMU monitor is redirectted to 144 | stdio (via argument `-monitor stdio`). Script `run-qemu` will start 145 | the emulator without GDB support; while `debug-qemu` enables GDB 146 | support: `-s` argument makes QEMU listens to port 1234 for GDB, while 147 | `-S` argument makes QEMU pauses at the beginning for GDB's `continue` 148 | command. After running `debug-qemu` and starting GDB, first type 149 | `target remote :1234` to connect to QEMU, then type command `continue` 150 | to resume the emulation. 151 | 152 | ### VirtualBox 153 | 154 | In the **Storage** page of the virtual machine settings, right click 155 | and select "Add Floppy Controller". And the select the image file 156 | `floppy.img` for floppy drive. In the **System** page of virtual 157 | machine settings, make sure that Floppy is checked for Boot order. 158 | 159 | Assuming the VM name is `yalo`, go to the root directory of the source 160 | code, where script `run-virtualbox` and `debug-virtualbox` are 161 | located. Run script `run-virtualbox` to start the emulator, or script 162 | `debug-virtualbox` to start the emulator with debug window. 163 | 164 | ## Software version 165 | 166 | So far, the development is done on Arch Linux. For above-mentioned 167 | software, the corresponding version is listed below: 168 | 169 | * SBCL: 1.4.10 or CCL 1.12 170 | * Emacs: 26.1 171 | * SLIME: 2.22 172 | * Bochs: 2.6.9 173 | * QEMU: 3.0.0 174 | * VirtualBox: 5.2.18 175 | -------------------------------------------------------------------------------- /bochs-debug-cmds: -------------------------------------------------------------------------------- 1 | continue 2 | -------------------------------------------------------------------------------- /cc/.gitignore: -------------------------------------------------------------------------------- 1 | *.fasl 2 | -------------------------------------------------------------------------------- /cc/a20.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; A20 address line related functions. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2015 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defparameter *a20* 14 | `( 15 | ;;; Enable A20 address line based on: 16 | ;;; http://www.independent-software.com/writing-your-own-toy-operating-system-enabling-the-a20-line/ 17 | ;;; Input: None 18 | ;;; Output: None 19 | ;;; Modified registers: AL, BL, CL 20 | enable-a20 21 | (call check-a20) 22 | (cmp ax 0) 23 | (jne .done) 24 | 25 | ;; Enable A20 based on BIOS 26 | (mov ax #x2401) 27 | (int #x15) 28 | 29 | (call check-a20) 30 | (cmp ax 0) 31 | (jne .done) 32 | 33 | ;; Enable A20 based on keyboard controller. 34 | (mov al kbd-ctrl-cmd-disable-keyboard) 35 | (call kbd-ctrl-send-cmd-16) 36 | (mov al kbd-ctrl-cmd-read-output-port) 37 | (call kbd-ctrl-send-cmd-16) 38 | (call wait-kbd-out-buf-16) 39 | (in al kbd-encoder-buf) 40 | (mov cl al) ; Save AL 41 | (mov al kbd-ctrl-cmd-write-output-port) 42 | (call kbd-ctrl-send-cmd-16) 43 | (mov al cl) ; Restore AL 44 | (or al 2) ; Enable A20 by set bit 1 to 1. 45 | (call kbd-encoder-send-cmd-16) 46 | (mov al kbd-ctrl-cmd-enable-keyboard) 47 | (call kbd-ctrl-send-cmd-16) 48 | (call wait-kbd-in-buf-16) 49 | 50 | (call check-a20) 51 | (cmp ax 0) 52 | (jne .done) 53 | 54 | ;; Enable A20 based on fast gate method. 55 | (in al #x92) 56 | (or al 2) 57 | (out #x92 al) 58 | 59 | (call check-a20) 60 | (cmp ax 0) 61 | (jne .done) 62 | 63 | .fail 64 | (mov si .a20-error-message) 65 | (call println-16) 66 | .panic 67 | (hlt) 68 | (jmp short .panic) 69 | .a20-error-message (db "ERROR: A20 address line cannot be enabled." 0) 70 | 71 | .done 72 | (ret) 73 | 74 | ;;; Check whether A20 is enabled or not. 75 | ;;; Input: None 76 | ;;; Output: AX=1 if A20 is enabled; AX=0 otherwise. 77 | ;;; The function writes different values to two addresses: 78 | ;;; 0000:0500 and ffff:0510. If A20 is not enabled, the two 79 | ;;; addresses are equivalent due to wrap around. 80 | ;;; This functions restores registers and states modified in the call. 81 | check-a20 82 | ;; Save flags and registers. 83 | (pushf) 84 | (push ds) 85 | (push es) 86 | (push di) 87 | (push si) 88 | ;; Set es:di = 0000:0500 89 | (xor ax ax) 90 | (mov es ax) 91 | (mov di #x500) 92 | ;; Set ds:si = ffff:0510 93 | (mov ax #xffff) 94 | (mov ds ax) 95 | (mov si #x510) 96 | ;; Save byte at es:di on stack. 97 | (es mov al (di)) 98 | (push ax) 99 | ;; Save byte at ds:si on stack. 100 | (ds mov al (si)) 101 | (push ax) 102 | (es mov byte (di), #x00) ; [es:di] = #x00 103 | (ds mov byte (si), #xff) ; [ds:si] = #xff 104 | (es cmp byte (di), #xff) ; Check memory wrap around. 105 | ;; Restore byte at ds:si 106 | (pop ax) 107 | (ds mov (si) al) 108 | ;; Restore byte at es:di 109 | (pop ax) 110 | (es mov (di) al) 111 | (mov ax 0) 112 | (je .exit) ; If A20 is disabled, return 0. 113 | (mov ax 1) ; Else, return 1 114 | .exit 115 | (pop si) 116 | (pop di) 117 | (pop es) 118 | (pop ds) 119 | (popf) 120 | (ret) 121 | )) 122 | -------------------------------------------------------------------------------- /cc/abi.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; x86-64 calling convention based on System V AMD64 ABI. 6 | ;;;; 7 | ;;;; Summary in 8 | ;;;; https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI 9 | ;;;; Basically, the first 6 integer or pointer arguments are 10 | ;;;; passed in RDI, RSI, RDX, RCX, R8, and R9, and rest are pushed 11 | ;;;; on stack. Return values are stored in RAX, and RDX if needed. 12 | ;;;; If callees wants to use RBX, RBP, and R12-R15, it must 13 | ;;;; restore their original values before returning control to the 14 | ;;;; caller. All other registers must be saved by the caller if it 15 | ;;;; wishes to preserve their values. 16 | ;;;; 17 | ;;;; References: 18 | ;;;; [1] https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf 19 | ;;;; License: 20 | ;;;; GNU General Public License v2 21 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 22 | ;;;; Copyright (C) 2015-2018 Yujian Zhang 23 | 24 | (in-package :cc) 25 | 26 | (defun call-function (function-name &optional saved-registers) 27 | "Used by the caller. The function adds push and pops around function 28 | calling automatically. It is assumed that RSP is aligned on 16 byte 29 | boundary before calling. if the number of `saved-registers` is odd, 30 | one more push/pop is added to ensure that RSP is aligned on 16 byte 31 | boundaring before calling the function." 32 | (let ((saved-registers* (if (oddp (length saved-registers)) 33 | (push (car saved-registers) saved-registers) 34 | saved-registers))) 35 | `(,@(mapcar #'(lambda (reg) (list 'push reg)) saved-registers*) 36 | (call ,function-name) 37 | ,@(mapcar #'(lambda (reg) (list 'pop reg)) (reverse saved-registers*))))) 38 | 39 | (defun def-fun (function-name saved-registers body) 40 | "Define a function following System V ABI. 41 | * saved-registers: a set of registers to be preserved, a subset 42 | of (rbx rsp rbp r12 r13 r14 r15). TODO: automatically detect 43 | which registers to save. 44 | 45 | This function automatically detect whether the function is a leaf 46 | function (which does not call other functions) or not. For a 47 | non-leaf function, stack frames are saved via rbp; while such 48 | additional operation is not done for leaf functions. 49 | 50 | Note that 128 byte red zone is not used." 51 | (when (and saved-registers 52 | (notevery #'(lambda (x) (member x '(rbx rsp rbp r12 r13 r14 r15))) saved-registers)) 53 | (error "def-fun: trying to save registers not in set (rbx rsp rbp r12 r13 r14 r15).")) 54 | (let* ((leaf? (notany #'(lambda (x) (and (listp x) (eq (car x) 'call))) body)) 55 | (prologue (unless leaf? 56 | '((push rbp) 57 | (mov rbp rsp)))) 58 | (epilogue (unless leaf? 59 | '((leave)))) 60 | ) 61 | `(,function-name 62 | ,@prologue 63 | ,@(mapcar #'(lambda (reg) (list 'push reg)) saved-registers) 64 | ,@body 65 | ,@(mapcar #'(lambda (reg) (list 'pop reg)) (reverse saved-registers)) 66 | ,@epilogue 67 | (ret) 68 | ))) 69 | 70 | (deftest test-abi () 71 | (check 72 | (equal (call-function 'read '(r10)) 73 | '((push r10) 74 | (push r10) 75 | (call read) 76 | (pop r10) 77 | (pop r10))) 78 | (equal (call-function 'write '(r10 r11)) 79 | '((push r10) 80 | (push r11) 81 | (call write) 82 | (pop r11) 83 | (pop r10))) 84 | (equal (def-fun 'read '(r12) '((xor eax eax))) 85 | '(read 86 | (push r12) 87 | (xor eax eax) 88 | (pop r12) 89 | (ret))) 90 | (equal (def-fun 'write '(r12 r13) '((move rdi 42) 91 | (call universe))) 92 | '(write 93 | (push rbp) 94 | (mov rbp rsp) 95 | (push r12) 96 | (push r13) 97 | (move rdi 42) 98 | (call universe) 99 | (pop r13) 100 | (pop r12) 101 | (leave) 102 | (ret))))) 103 | -------------------------------------------------------------------------------- /cc/address.asm: -------------------------------------------------------------------------------- 1 | ;; NASM code for cross check the assembly output from test-cc.lisp. 2 | ;; The test is performed as follows: 3 | ;; 1. Run NASM with: /usr/local/bin/nasm -o address.img address.asm 4 | ;; 2. In CL REPL, compare the output with (equal (read-image "address.img") (asm *address-asm*)) 5 | ;; Note that above nasm command assumes the usage of nasm installed from brew. 6 | 7 | org 7C00h 8 | 9 | bits 16 10 | mov [bp], es 11 | mov [bx+si], ds 12 | mov [bx+di], es 13 | mov [bp+si], ds 14 | mov [bp+di], ss 15 | mov [si], ds 16 | mov [di], cs 17 | mov [32330], ds 18 | mov [msg], ds 19 | mov [bx], cs 20 | mov [bx+si+1], ds 21 | mov [bx+di+2], es 22 | mov [bp+si+3], ds 23 | mov [bp+di+4], ss 24 | mov [si+5], ds 25 | mov [di+6], cs 26 | mov [bp+7], ds 27 | mov [bx+8], cs 28 | mov ds, [di] 29 | mov ds, [bx+si+1001] 30 | mov es, [bx+di+1002] 31 | mov ds, [bp+si+1003] 32 | mov ss, [bp+di+1004] 33 | mov ds, [si+1005] 34 | mov es, [di+1006] 35 | mov ds, [bp+1007] 36 | mov es, [bx+1008] 37 | 38 | bits 32 39 | mov [ebp], ebx 40 | mov [esp], ecx 41 | mov [123456], edx 42 | mov [eax], edx 43 | mov [ebp+36], ecx 44 | mov [edi+1234], edx 45 | mov [esi+123456], ecx 46 | mov [esp+23h], ebx 47 | mov [esp+12345678h], ecx 48 | mov [eax+ebx], ecx 49 | mov [esi+edi], edx 50 | mov [esi+ebp], edx 51 | mov [eax*2+esi], edx 52 | mov [esi*2+ebp+123], edx 53 | mov [edi*2+ebx+8], ecx 54 | mov [ecx*4+ebp+123], edx 55 | mov [esi*4+edx+8], ecx 56 | mov [edx*8+ebp+123456], ebx 57 | mov [edi*8+ecx+8], edx 58 | 59 | bits 64 60 | mov [rbp], rbx 61 | mov [rsp], rcx 62 | mov [123456], rdx 63 | mov [rax], rdx 64 | mov [rbp+36], rcx 65 | mov [rdi+1234], rdx 66 | mov [rsi+123456], rcx 67 | mov [rsp+23h], rbx 68 | mov [rsp+12345678h], rcx 69 | mov [rax+rbx], rcx 70 | mov [rsi+rdi], rdx 71 | mov [rsi+rbp], rdx 72 | mov [rax*2+rsi], rdx 73 | mov [rsi*2+rbp+123], rdx 74 | mov [rdi*2+rbx+8], rcx 75 | mov [rcx*4+rbp+123], rdx 76 | mov [rsi*4+rdx+8], rcx 77 | mov [rdx*8+rbp+123456], rbx 78 | mov [rdi*8+rcx+8], rdx 79 | msg: 80 | db "Hello World! " 81 | endmsg: 82 | -------------------------------------------------------------------------------- /cc/arith.asm: -------------------------------------------------------------------------------- 1 | ;; NASM code for cross check the assembly output from test-cc.lisp. 2 | ;; The test is performed as follows: 3 | ;; 1. Run NASM with: /usr/local/bin/nasm -o arith.img arith.asm 4 | ;; 2. In CL REPL, compare the output with (equal (read-image "arith.img") (asm *arith-asm*)) 5 | ;; Note that above nasm command assumes the usage of nasm installed from brew. 6 | 7 | org 7C00h 8 | bits 16 9 | 10 | add al, 8 11 | add ax, 1000 12 | add bl, 3 13 | add byte [msg], 4 14 | add bx, 1234 15 | add word [msg], 5678 16 | add cx, byte 9 17 | add word [msg], byte 12 18 | add al, bl 19 | add [msg], ch 20 | add cx, bx 21 | add word [msg], dx 22 | add ch, byte [msg] 23 | add dx, word [msg] 24 | and al, 8 25 | and ax, 1000 26 | and bl, 3 27 | and byte [msg], 4 28 | and bx, 1234 29 | and word [msg], 5678 30 | and cx, byte 9 31 | and word [msg], byte 12 32 | and al, bl 33 | and [msg], ch 34 | and cx, bx 35 | and word [msg], dx 36 | and ch, byte [msg] 37 | and dx, word [msg] 38 | cmp al, 8 39 | cmp ax, 1000 40 | cmp bl, 3 41 | cmp byte [msg], 4 42 | cmp bx, 1234 43 | cmp word [msg], 5678 44 | cmp cx, byte 9 45 | cmp word [msg], byte 12 46 | cmp al, bl 47 | cmp [msg], ch 48 | cmp cx, bx 49 | cmp word [msg], dx 50 | cmp ch, byte [msg] 51 | cmp dx, word [msg] 52 | dec bx 53 | dec eax 54 | dec dl 55 | dec byte [msg] 56 | dec word [bp+si+3] 57 | dec dword [msg] 58 | div ch 59 | div byte [msg] 60 | div di 61 | div word [bp+si+3] 62 | inc bx 63 | inc eax 64 | inc dl 65 | inc byte [msg] 66 | inc word [bp+si+3] 67 | inc dword [msg] 68 | mul ch 69 | mul byte [msg] 70 | mul di 71 | mul word [bp+si+3] 72 | neg ch 73 | neg byte [msg] 74 | neg di 75 | neg word [bp+si+3] 76 | not ch 77 | not byte [msg] 78 | not di 79 | not word [bp+si+3] 80 | or al, 8 81 | or ax, 1000 82 | or bl, 3 83 | or byte [msg], 4 84 | or bx, 1234 85 | or word [msg], 5678 86 | or cx, byte 9 87 | or word [msg], byte 12 88 | or al, bl 89 | or [msg], ch 90 | or cx, bx 91 | or word [msg], dx 92 | or ch, byte [msg] 93 | or dx, word [msg] 94 | shl dh, 1 95 | shl byte [msg], 1 96 | shl dh, cl 97 | shl byte [msg], cl 98 | shl dh, 5 99 | shl byte [msg], 5 100 | shl dx, 1 101 | shl word [msg], 1 102 | shl dx, cl 103 | shl word [msg], cl 104 | shl dx, 5 105 | shl word [msg], 5 106 | shr dh, 1 107 | shr byte [msg], 1 108 | shr dh, cl 109 | shr byte [msg], cl 110 | shr dh, 5 111 | shr byte [msg], 5 112 | shr dx, 1 113 | shr word [msg], 1 114 | shr dx, cl 115 | shr word [msg], cl 116 | shr dx, 5 117 | shr word [msg], 5 118 | sub al, 8 119 | sub ax, 1000 120 | sub bl, 3 121 | sub byte [msg], 4 122 | sub bx, 1234 123 | sub word [msg], 5678 124 | sub cx, byte 9 125 | sub word [msg], byte 12 126 | sub al, bl 127 | sub [msg], ch 128 | sub cx, bx 129 | sub word [msg], dx 130 | sub ch, byte [msg] 131 | sub dx, word [msg] 132 | test al, 8 133 | test ax, 1000 134 | test bl, 3 135 | test byte [msg], 4 136 | test bx, 1234 137 | test word [msg], 5678 138 | test al, bl 139 | test [msg], ch 140 | test cx, bx 141 | test word [msg], dx 142 | xor al, 8 143 | xor ax, 1000 144 | xor bl, 3 145 | xor byte [msg], 4 146 | xor bx, 1234 147 | xor word [msg], 5678 148 | xor cx, byte 9 149 | xor word [msg], byte 12 150 | xor al, bl 151 | xor [msg], ch 152 | xor cx, bx 153 | xor word [msg], dx 154 | xor ch, byte [msg] 155 | xor dx, word [msg] 156 | 157 | [bits 32] 158 | 159 | add ax, 1000 160 | dec dx 161 | dec ebp 162 | inc dx 163 | inc ebp 164 | 165 | [bits 64] 166 | 167 | adc rax, 12345h 168 | add ebx, 1000 169 | add rax, 10010203h 170 | ; add rax, 10 171 | add rbx, 267 172 | add r15, 123456h 173 | add r10d, byte 3 174 | add sil, 6 175 | add r9b, 8 176 | add r10, rbx 177 | add rsi, [rbx] 178 | dec di 179 | dec ecx 180 | dec r10 181 | div ebx 182 | inc di 183 | inc ecx 184 | inc r10 185 | mul dword [rbx] 186 | neg rcx 187 | not qword [rbx] 188 | sbb rbx, rdx 189 | test rax, 123456789 190 | test r12, 11223344 191 | test qword [rdi], 9966 192 | test rdx, rdi 193 | test qword [rdx], r9 194 | 195 | msg: 196 | db "Hello World! " 197 | endmsg: 198 | -------------------------------------------------------------------------------- /cc/bga.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Bochs VBE Extensions, see http://wiki.osdev.org/BGA 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2012 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defparameter *bga* 14 | `( 15 | ;;; BGA constants 16 | (equ vbe-dispi-ioport-index #x1ce) 17 | (equ vbe-dispi-ioport-data #x1cf) 18 | (equ vbe-dispi-index-id 0) 19 | (equ vbe-dispi-index-xres 1) 20 | (equ vbe-dispi-index-yres 2) 21 | (equ vbe-dispi-index-bpp 3) 22 | (equ vbe-dispi-index-enable 4) 23 | (equ vbe-dispi-index-bank 5) 24 | (equ vbe-dispi-index-virt-width 6) 25 | (equ vbe-dispi-index-virt-height 7) 26 | (equ vbe-dispi-index-x-offset 8) 27 | (equ vbe-dispi-index-y-offset 9) 28 | ;; It seems that VirtualBox only supports BGA up to #xb0c4. See 29 | ;; http://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/Graphics/BIOS/vbe_display_api.txt 30 | (equ vbe-dispi-id2 #xb0c2) 31 | (equ vbe-dispi-id4 #xb0c4) 32 | (equ vbe-dispi-id5 #xb0c5) 33 | (equ vbe-dispi-bpp-32 #x20) 34 | (equ vbe-dispi-enabled 1) 35 | (equ vbe-dispi-disabled 0) 36 | 37 | ;;; Write index/data to one BGA register. 38 | ;;; Input: 39 | ;;; AL: index value 40 | ;;; BX: data value 41 | ;;; Output: None 42 | ;;; Modified registers: DX 43 | bga-write-register 44 | (mov dx vbe-dispi-ioport-index) 45 | (out dx al) 46 | (mov dx vbe-dispi-ioport-data) 47 | (mov ax bx) 48 | (out dx ax) 49 | (ret) 50 | 51 | ;;; Read BGA register. 52 | ;;; Input: 53 | ;;; AL: index value 54 | ;;; Output: in AX 55 | ;;; Modified registers: DX 56 | bga-read-register 57 | (mov dx vbe-dispi-ioport-index) 58 | (out dx al) 59 | (mov dx vbe-dispi-ioport-data) 60 | (in ax dx) 61 | (ret) 62 | 63 | ;;; Check whether BGA is available. 64 | ;;; Input: None 65 | ;;; Output: CF is set if BGA is unavailable. 66 | bga-available 67 | (clc) 68 | (mov al vbe-dispi-index-id) 69 | (call bga-read-register) 70 | (cmp ax vbe-dispi-id2) 71 | (jb no-bga) 72 | (ret) 73 | no-bga 74 | (stc) 75 | (ret) 76 | 77 | ;;; Set BGA mode. 78 | set-bga-mode 79 | (mov al vbe-dispi-index-enable) 80 | (mov bx vbe-dispi-disabled) 81 | (call bga-write-register) 82 | (mov al vbe-dispi-index-xres) 83 | (mov bx 800) 84 | (call bga-write-register) 85 | (mov al vbe-dispi-index-yres) 86 | (mov bx 600) 87 | (call bga-write-register) 88 | (mov al vbe-dispi-index-bpp) 89 | (mov bx vbe-dispi-bpp-32) 90 | (call bga-write-register) 91 | (mov al vbe-dispi-index-enable) 92 | (mov bx vbe-dispi-enabled) 93 | (call bga-write-register) 94 | (ret))) 95 | -------------------------------------------------------------------------------- /cc/bitmap.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Bitmap functions. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2015 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defparameter *bitmap-prologue* 14 | `(;;; Bounds check. 15 | (cmp rsi (rdi)) 16 | (jb .continue) 17 | (mov rsi bitmap-overflow-message) 18 | ,@(call-function 'panic) 19 | .continue)) 20 | 21 | (defparameter *bitmap* 22 | `( 23 | ;;; Bitmap consists of a stream of bytes, representing a bit array. 24 | ;;; The first qword stores the size (in bits) of the bitmap. 25 | ;;; We assume the multiples of qwords are reserved to storet the bitmap. 26 | ;;; 27 | ;;; Typically functions have two input parameters: 28 | ;;; start-address: the starting address of the bitmap. 29 | ;;; bit-position: the bit position in the bit array, starting from 0. 30 | 31 | ;; The offset starting from which where actual bitmap is stored. 32 | (equ bitmap-offset 8) 33 | ;; Divide by 64 to get qword offset 34 | (equ bitmap-shift 6) 35 | ;; Mask to get the bit index within the qword. 36 | (equ bitmap-mask (1- (expt 2 bitmap-shift))) 37 | 38 | ;;; Function bitmap-init. Initialize the bitmap. 39 | ;;; Perform the following: 40 | ;;; 1) Set the size field. 41 | ;;; 2) Initialize all bits to 0. 42 | ;;; We assume multiples of qwords are reserved to store the bitmap. 43 | ;;; This has the benefit that we have sentinel element for bitmap-scan 44 | ;;; if the bitmap size is not the multiple of 64 (qword). 45 | ;;; Input: 46 | ;;; RDI: start-address, there is no requirement that it should be qword aligned. 47 | ;;; RSI: size in bits 48 | ,@(def-fun 'bitmap-init nil 49 | `( 50 | (mov (rdi) rsi) 51 | (add rdi bitmap-offset) 52 | (mov rcx rsi) 53 | (add rcx bitmap-mask) 54 | (shr rcx bitmap-shift) ; RCX now is: ceil(rsi / 64) 55 | (xor eax eax) 56 | (cld) 57 | (rep stosq))) 58 | 59 | ;;; Function bitmap-set. Set the bit (i.e. to 1). 60 | ;;; Input: 61 | ;;; RDI: start-address. 62 | ;;; RSI: bit-position. 63 | ,@(def-fun 'bitmap-set nil 64 | `( 65 | ,@*bitmap-prologue* 66 | (mov rdx rsi) ; RDX: qword offset 67 | (shr rdx bitmap-shift) 68 | (and esi bitmap-mask) 69 | (bts (rdx*8 rdi bitmap-offset) rsi))) 70 | 71 | ;;; Function bitmap-unset. Unset the bit (i.e. to 0). 72 | ;;; Input: 73 | ;;; RDI: start-address. 74 | ;;; RSI: bit-position. 75 | ,@(def-fun 'bitmap-unset nil `( 76 | ,@*bitmap-prologue* 77 | (mov rdx rsi) ; RDX: qword offset 78 | (shr rdx bitmap-shift) 79 | (and esi bitmap-mask) 80 | (btr (rdx*8 rdi bitmap-offset) rsi))) 81 | 82 | ;;; Function bitmap-test. Returns corresponding bit in RDX. 83 | ;;; Input: 84 | ;;; RDI: start-address. 85 | ;;; RSI: bit-position. 86 | ;;; Output: 87 | ;;; RAX: bit value 88 | ,@(def-fun 'bitmap-test nil 89 | `( 90 | ,@*bitmap-prologue* 91 | (xor eax eax) ; Prepare 92 | (mov ecx 1) ; returning results. 93 | (mov rdx rsi) ; RDX: qword offset 94 | (shr rdx bitmap-shift) 95 | (and esi bitmap-mask) 96 | (bt (rdx*8 rdi bitmap-offset) rsi) 97 | (cmovc rax rcx))) 98 | 99 | ;;; Function bitmap-scan. Returns the index of the 1st bit which is 0. 100 | ;;; If every bit is 1, return -1. 101 | ;;; Input: 102 | ;;; RDI: start-address 103 | ;;; Output: 104 | ;;; RAX: corresponding index 105 | ,@(def-fun 'bitmap-scan nil 106 | `( 107 | (mov rcx (rdi)) 108 | (add rcx bitmap-mask) ; Scan ceil((rdi) / 64) 109 | (shr rcx bitmap-shift) 110 | (xor edx edx) 111 | .start 112 | (mov r8 (rdx*8 rdi bitmap-offset)) 113 | (not r8) 114 | (bsf r9 r8) 115 | (jnz .scan-complete) 116 | ;; All zero means that the original qword contains all 1 (we use "NOT" instruction). 117 | (inc rdx) 118 | (loop .start) 119 | (jmp short .not-found) 120 | .scan-complete 121 | (mov rax rdx) 122 | (shl rax bitmap-shift) 123 | (add rax r9) ; RAX is now the index. 124 | (cmp rax (rdi)) 125 | (jb .done) 126 | .not-found 127 | (mov rax -1) 128 | .done 129 | )) 130 | 131 | ;;; Function bitmap-count-1. Returns the count of 1 in the bitmap. 132 | ;;; Input: 133 | ;;; RDI: start-address 134 | ;;; Output: 135 | ;;; RAX: count of 1. 136 | ,@(def-fun 'bitmap-count-1 nil 137 | `( 138 | (mov rcx (rdi)) 139 | (add rcx bitmap-mask) ; Scan ceil((rdi) / 64) 140 | (shr rcx bitmap-shift) 141 | (xor eax eax) ; RAX: count of 1 142 | (xor edx edx) ; RDX: index to the qword element 143 | .start 144 | (popcnt r8 (rdx*8 rdi bitmap-offset)) 145 | (add rax r8) 146 | (inc rdx) 147 | (loop .start))) 148 | 149 | ;;; Function bitmap-count-0. Returns the count of 0 in the bitmap. 150 | ;;; Input: 151 | ;;; RDI: start-address 152 | ;;; Output: 153 | ;;; RAX: count of 0. 154 | ,@(def-fun 'bitmap-count-0 nil 155 | `( 156 | ,@(call-function 'bitmap-count-1) 157 | (neg rax) 158 | (add rax (rdi)))) 159 | 160 | ;;; Bitmap regression test. 161 | ,@(regression-container 162 | (def-fun 'bitmap-regression nil 163 | `( 164 | (equ bitmap-regression-addr #xffffffff80400000) 165 | (mov rdi bitmap-regression-addr) 166 | (mov rsi 100) 167 | ,@(call-function 'bitmap-init) 168 | (mov rdi bitmap-regression-addr) 169 | ,@(call-function 'bitmap-count-1) 170 | (cmp rax 0) 171 | (jne .error) 172 | ,@(call-function 'bitmap-count-0) 173 | (cmp rax 100) 174 | (jne .error) 175 | (mov rdi bitmap-regression-addr) 176 | (mov rsi 0) 177 | ,@(call-function 'bitmap-set) 178 | ,@(call-function 'bitmap-count-0) 179 | (cmp rax 99) 180 | (jne .error) 181 | (mov rsi 1) 182 | ,@(call-function 'bitmap-set) 183 | ,@(call-function 'bitmap-count-0) 184 | (cmp rax 98) 185 | (jne .error) 186 | ,@(call-function 'bitmap-scan) 187 | (cmp rax 2) 188 | (jne .error) 189 | (mov rax #xffffffffffffffff) 190 | (mov (rdi 8) rax) 191 | ,@(call-function 'bitmap-count-0) 192 | (cmp rax 36) 193 | (jne .error) 194 | ,@(call-function 'bitmap-scan) 195 | (cmp rax 64) 196 | (jne .error) 197 | (mov rsi 64) 198 | ,@(call-function 'bitmap-set) 199 | ,@(call-function 'bitmap-count-0) 200 | (cmp rax 35) 201 | (jne .error) 202 | ,@(call-function 'bitmap-scan) 203 | (cmp rax 65) 204 | (jne .error) 205 | (mov rsi 65) 206 | ,@(call-function 'bitmap-set) 207 | ,@(call-function 'bitmap-count-0) 208 | (cmp rax 34) 209 | (jne .error) 210 | ,@(call-function 'bitmap-scan) 211 | (cmp rax 66) 212 | (jne .error) 213 | (mov rsi 67) 214 | ,@(call-function 'bitmap-set) 215 | ,@(call-function 'bitmap-scan) 216 | (cmp rax 66) 217 | (jne .error) 218 | (mov rsi 64) 219 | ,@(call-function 'bitmap-unset) 220 | ,@(call-function 'bitmap-count-0) 221 | (cmp rax 34) 222 | (jne .error) 223 | ,@(call-function 'bitmap-scan) 224 | (cmp rax 64) 225 | (jne .error) 226 | (jmp short .done) 227 | .error 228 | (mov rdi bitmap-regression-error-message) 229 | ,@(call-function 'println) 230 | .done 231 | ))) 232 | 233 | bitmap-overflow-message (db "ERROR: bitmap index exceeds bounds." 0) 234 | bitmap-regression-error-message (db "Regression test fails for bitmap." 0) 235 | )) 236 | -------------------------------------------------------------------------------- /cc/bochs.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; BOCHS specific functions. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2018 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defparameter *bochs* 14 | `( 15 | (equ bochs-shutdown-port #x8900) 16 | ;;; Shutdown computer. 17 | ;;; Note that although computer is already shutdown after sending the special string, 18 | ;;; a function is still defined for simplicity. 19 | ;;; Input: None 20 | ;;; Output: Noneq 21 | ,@(def-fun 'bochs-shutdown nil 22 | `( 23 | .start 24 | (mov dx bochs-shutdown-port) 25 | (mov rsi shutdown-str) 26 | .loop 27 | (lodsb) 28 | (out dx al) 29 | (test al al) 30 | (jz .done) 31 | (jmp short .loop) 32 | .done)) 33 | 34 | shutdown-str (db "Shutdown" 0) 35 | )) 36 | -------------------------------------------------------------------------------- /cc/bootloader.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Bootloader. 6 | ;;;; 7 | ;;;; Switch to 32 bit protected mode and 64 bit long mode is mainly based on 8 | ;;;; Section 14.8 (Long-Mode Initialization Example) of 9 | ;;;; [1] AMD64 Architecture Programmer's Manual Volume 2: System Programming. 10 | ;;;; Publication No. 24593; Revision: 3.25 11 | ;;;; License: 12 | ;;;; GNU General Public License v2 13 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 14 | ;;;; Copyright (C) 2009-2015 Yujian Zhang 15 | 16 | (in-package :cc) 17 | 18 | (defparameter *bootloader* 19 | `(;;;==================== 16 bit real mode ==================== 20 | (bits 16) 21 | (org #x7c00) 22 | 23 | ;; Setup segments and stack. 24 | (cli) 25 | (xor ax ax) 26 | (mov ds ax) 27 | (mov es ax) 28 | ;; From http://wiki.osdev.org/Memory_Map_(x86), 29 | ;; #x7e00 ~ #x7ffff is guaranteed to be available for use, therefore set 30 | ;; ss:sp = 7000:ff00 31 | (mov ax #x7000) 32 | (mov ss ax) 33 | (mov sp #xff00) 34 | (sti) 35 | 36 | ;; Load other sectors from floppy disk. 37 | ;; AL: # of sectors 38 | (mov ax (+ #x200 (ceiling (+ (- kernel-before-relocation stage-2) 39 | (- kernel-virtual-end kernel-virtual-start)) 40 | 512))) 41 | (mov bx stage-2) ; ES:BX is destination 42 | (mov cx 2) ; CH: cylinder; CL: sector 43 | (xor dx dx) ; DH: head; DL: drive 44 | (int #x13) 45 | 46 | (jmp near stage-2) 47 | 48 | ;; Fill up to 510 bytes. 49 | (times (- 510 (- $ $$)) db 0) 50 | 51 | (dw #xaa55) ; Boot sector signature 52 | 53 | ;; Stage 2. 54 | stage-2 55 | 56 | ;; Initialize text mode. 57 | (call init-text-mode-16) 58 | 59 | ;; Check whether BGA is available 60 | ;; The following two lines are disabled for now as BGA mode is not used currently. 61 | ;; If not disabled, error will be thrown on VirtualBox (however osdev.org actually says that 62 | ;; VirtualBox supports BGA: http://wiki.osdev.org/BGA) 63 | ;;(call bga-available) 64 | ;;(jc no-bga-error) 65 | ;; Set target screen mode. 66 | ;(call set-bga-mode) 67 | ;; Show all red. 68 | ;(mov ecx ,(/ 65536 4)) 69 | ;(mov eax #xa000) 70 | ;(mov es ax) 71 | ;(xor edi edi) 72 | ;(mov eax #xff0000) ; Red 73 | ;(cld) 74 | ;(rep stosd) 75 | 76 | ;; Check whether CPU supports Long Mode or not. 77 | (call check-cpu) 78 | (jc no-long-mode-error) 79 | 80 | ;; Enable A20 line. 81 | (call enable-a20) 82 | 83 | ;; Get memory map. 84 | (call get-memory-map) 85 | 86 | (jmp near switch-to-protected-mode) 87 | 88 | ;; A20 and keyboard related include from keyboard.lisp. 89 | ,@*keyboard-constants* 90 | ,@*keyboard-16* 91 | ,@*a20* 92 | 93 | ;; Memory map include from memory.lisp. 94 | ,@*memory-16* 95 | 96 | ;; Function check-cpu. Use CPUID to check if the process supports long mode. 97 | ;; From section 14.8 (Long-Mode Initialization Example) of [1]. 98 | ;; If long mode is supported, CF is cleared; otherwise CF is set. 99 | 100 | check-cpu 101 | (mov eax #x80000000) 102 | (cpuid) 103 | (cmp eax #x80000000) ; Whether any extended function > 0x800000000 is available? 104 | (jbe no-long-mode) 105 | (mov eax #x80000001) 106 | (cpuid) 107 | (bt edx 29) ; Test if long mode is supported. 108 | (jnc no-long-mode) 109 | (clc) 110 | (ret) 111 | no-long-mode 112 | (stc) 113 | (ret) 114 | 115 | no-long-mode-error 116 | (mov si no-long-mode-message) 117 | (call println-16) 118 | .panic 119 | (hlt) 120 | (jmp short .panic) 121 | no-long-mode-message (db "ERROR: CPU does not support long mode." 0) 122 | 123 | ;; Include content from vga-text.lisp. 124 | ,@*vga-text-16* 125 | 126 | ;;; Global Descriptor Table (GDT). 127 | ;;; 32 bit GDT entries are according to 128 | ;;; http://www.brokenthorn.com/Resources/OSDev8.html 129 | ;;; 64 bit GDT entries are according to section 14.8 130 | ;;; (Long-Mode Initialization Example) of [1]. 131 | gdt 132 | ;; Null descriptor 133 | (dd 0) 134 | (dd 0) 135 | ;; 32 bit code descriptor. 136 | (equ code-selector-32 (- $ gdt)) 137 | (dw #xffff) ; Limit low 138 | (dw 0) ; Base low 139 | (db 0) ; Base middle 140 | (db #b10011010) ; Access 141 | (db #b11001111) ; Granularity 142 | (db 0) ; Base high 143 | ;; 32 bit data descriptor. 144 | (equ data-selector-32 (- $ gdt)) 145 | (dw #xffff) ; Limit low 146 | (dw 0) ; Base low 147 | (db 0) ; Base middle 148 | (db #b10010010) ; Access 149 | (db #b11001111) ; Granularity 150 | (db 0) ; Base high 151 | ;; 64 bit code descriptor. 152 | (equ code-selector-64 (- $ gdt)) 153 | (dw 0) ; Limit low (ingored) 154 | (dw 0) ; Base low (ingored) 155 | (db 0) ; Base middle (ingored) 156 | (db #b10011000) ; Access 157 | (db #b00100000) ; Granularity 158 | (db 0) ; Base high (ingored) 159 | ;; 64 bit data descriptor (read/write). 160 | (equ data-selector-64 (- $ gdt)) 161 | (dw 0) ; Limit low (ingored) 162 | (dw 0) ; Base low (ingored) 163 | (db 0) ; Base middle (ingored) 164 | (db #b10010000) ; Access 165 | (db #b00000000) ; Granularity 166 | (db 0) ; Base high (ingored) 167 | end-gdt 168 | pgdt 169 | (dw (- end-gdt gdt 1)) ; Limit (size of GDT) 170 | (dd gdt) ; Base of GDT 171 | 172 | (align 4) 173 | idt 174 | .length (dw 0) 175 | .base (dd 0) 176 | 177 | switch-to-protected-mode 178 | (cli) 179 | (lgdt (pgdt)) ; Load GDT 180 | ;; Enter protected mode by setting CR0.PE = 1. 181 | (mov eax #b11) 182 | (mov cr0 eax) 183 | ;; Far jump to turn on protected mode. The following code is equivalent to 184 | ;; (jmp far code-selector-32:protected-mode) 185 | (db #xea) ; Far jump 186 | (dw protected-mode) 187 | (dw code-selector-32) 188 | 189 | ;;;==================== 32 bit protected mode ==================== 190 | 191 | protected-mode 192 | (bits 32) 193 | ;; Setup registers. 194 | (mov ax data-selector-32) 195 | (mov ss ax) 196 | (mov esp #x90000) 197 | (mov ds ax) 198 | (mov es ax) 199 | 200 | switch-to-long-mode 201 | (call32 setup-paging) 202 | 203 | ;; Enable 64 bit page-translation-table entries by setting 204 | ;; CR4.PAE=1. Paging is not enabled until long mode is 205 | ;; enabled. 206 | (mov eax cr4) 207 | (bts eax 5) 208 | (mov cr4 eax) 209 | 210 | ;; Initialize 64-bit CR3 to point to the base of PML4 page table. 211 | ;; Note that PML4 table must be below 4 GB. 212 | (mov eax pml4-base) 213 | (mov cr3 eax) 214 | 215 | ;; Enable long mode (set EFER.LME = 1). 216 | (mov ecx #xc0000080) ; EFER MSR number. 217 | (rdmsr) ; Read EFER. 218 | (bts eax 8) ; Set LME = 1. 219 | (wrmsr) ; Write EFER. 220 | 221 | ;; Enable paging to activate long mode (set CR0.PG = 1). 222 | (mov eax cr0) ; Read CR0. 223 | (bts eax 31) ; Set PE = 1. 224 | (mov cr0 eax) ; Write CR0. 225 | 226 | ;; Jump from 32 bit compatibility mode to 64 bit code segment. 227 | ;; Far jump to turn on long mode. The following code is equivalent to 228 | ;; (jmp far code-selector-64:protected-mode) 229 | (db #x66) 230 | (db #xea) ; Far jump 231 | (dw long-mode) ; In [1], dd is used instead of dw. 232 | (dw code-selector-64) 233 | 234 | ,@*paging-32* 235 | ,@*memory-32* 236 | 237 | ,@*kernel*)) 238 | -------------------------------------------------------------------------------- /cc/cc.asd: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; ASDF definition. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | 10 | (defpackage #:cc-system 11 | (:use #:cl #:asdf)) 12 | (in-package #:cc-system) 13 | 14 | (defsystem cc 15 | :description "Cross compiler for yalo." 16 | :serial t 17 | :components 18 | ((:file "package") 19 | (:file "util") 20 | (:file "unit-test") 21 | (:file "config") 22 | (:file "abi") 23 | (:file "bitmap") 24 | (:file "memory") 25 | (:file "paging") 26 | (:file "bga") 27 | (:file "vga-text") 28 | (:file "keyboard") 29 | (:file "a20") 30 | (:file "bochs") 31 | (:file "kernel") 32 | (:file "bootloader") 33 | (:file "x86-64-syntax") 34 | (:file "lap") 35 | (:file "nasm") 36 | (:file "test-cc") 37 | (:file "test"))) 38 | -------------------------------------------------------------------------------- /cc/config.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Configuration for the kernel. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2018 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defparameter *include-regression-test* nil 14 | "Whether to include regression tests in the kernel: 15 | - t: Include regression tests 16 | - nil: NOT include regression tests") 17 | 18 | (defun regression-container (forms) 19 | "Include the FORMS if *include-regression-test* is T" 20 | (when *include-regression-test* 21 | forms)) 22 | -------------------------------------------------------------------------------- /cc/kernel.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; 64 bit long mode kernel code. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2015-2018 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defparameter *kernel* 14 | `( 15 | ;;;==================== 64 bit long mode ==================== 16 | 17 | long-mode 18 | (bits 64) 19 | 20 | ;; Load constant definitions 21 | ,@*vga-text-constants* 22 | 23 | ;; Setup stack's linear address. See the related 16 bit code for reason. 24 | (mov rsp #x7ff00) 25 | 26 | ;; Reuse previous 32 bit GDT (as we don't consume more than 4 GB memory. So skip loading 64 bit GDT. 27 | ;; (lgdt (pgdt)) 28 | 29 | ;; Load 64 bit IDT. So far IDT has zero length, therefore any NMI causes a triple fault. 30 | ;;(lidt (idt)) 31 | 32 | ;; Move kernel to physical address #x100000, which is virtual address 33 | ;; #xffffffff80100000. 34 | (mov rsi kernel-before-relocation) 35 | (mov rdi kernel-physical-base) 36 | (mov rcx (- kernel-virtual-end kernel-virtual-start)) 37 | (rep movsb) 38 | 39 | ;; Jump to higher half kernel in 64 bit trampoline. 40 | (mov rdi kernel-virtual-start) 41 | (push rdi) 42 | (ret) ; Use push/ret together to implement a jmp. 43 | 44 | ;; Fill up to multiple of sectors, otherwise VirtualBox complains. 45 | (align 512) 46 | 47 | kernel-before-relocation 48 | 49 | (equ kernel-physical-base #x100000) 50 | (org (+ kernel-virtual-base kernel-physical-base)) 51 | 52 | kernel-virtual-start 53 | 54 | ;; Setup stack's linear address again. 55 | (mov rsp (+ kernel-virtual-start #x100000)) 56 | 57 | ,@(call-function 'unmap-lower-memory) 58 | 59 | ,@(call-function 'pmm-init) 60 | 61 | ,@(call-function 'clear) 62 | 63 | ;; Reload all data segments with null. 64 | (xor ax ax) 65 | (mov ss ax) 66 | (mov ds ax) 67 | (mov es ax) 68 | (mov fs ax) 69 | (mov gs ax) 70 | 71 | (mov rdi banner) 72 | ,@(call-function 'println) 73 | (jmp short read-start) 74 | banner (db "Start your journey on yalo v0.0.1!" 0) 75 | 76 | ;; So far this function is not called. Actually calling it 77 | ;; resulting in some issues 78 | ;; TODO 79 | ,@(call-function 'init-keyboard) 80 | 81 | ;;; REPL: read 82 | read-start 83 | (mov rdi repl) 84 | ,@(call-function 'print) 85 | (jmp short read) 86 | repl (db "REPL> " 0) 87 | (equ prompt-length (- $ repl 1)) 88 | read 89 | ,@(call-function 'getchar) 90 | (cmp al 10) 91 | (je eval-start) 92 | (cmp al 0) ; Non-printable character. 93 | (jz read) 94 | (cmp al ascii-backspace) 95 | (jnz .show) 96 | ,@(call-function 'backspace-char) 97 | (jmp short read) 98 | .show 99 | (mov dil al) 100 | ,@(call-function 'putchar) 101 | (jmp short read) 102 | 103 | ;;; REPL: eval 104 | eval-start 105 | 106 | ;;; REPL: print 107 | ,@(call-function 'printlf) 108 | ,@(call-function 'printlf) 109 | 110 | ;;; REPL: loop 111 | (jmp short read-start) 112 | 113 | ;; (bits 16) 114 | 115 | ;; no-bga-error 116 | ;; (mov si no-bga-message) 117 | ;; (call println-16) 118 | ;; .panic 119 | ;; (hlt) 120 | ;; (jmp short .panic) 121 | ;; no-bga-message (db "ERROR: BGA not available." 0) 122 | 123 | (bits 64) 124 | 125 | ;; Include 64 bit paging related functions from paging.lisp 126 | ,@*paging* 127 | 128 | ;; Include 64 bit memory related functions from memory.lisp 129 | ,@*memory* 130 | 131 | ;; Include content from bga.lisp. 132 | ;;,@*bga* 133 | 134 | ;; Include content from vga-text.lisp. 135 | ,@*vga-text* 136 | 137 | ;; Include content from keyboard.lisp. 138 | ,@*keyboard* 139 | 140 | ;; Include content from bitmap.lisp. 141 | ,@*bitmap* 142 | 143 | ;; Include content from bochs.lisp. 144 | ,@*bochs* 145 | 146 | ;; Function panic. Display error message and halt the computer. 147 | ,@(def-fun 'panic nil 148 | `( 149 | ,@(call-function 'println) 150 | .panic 151 | (hlt) 152 | (jmp short .panic))) 153 | 154 | ;; Fill up to multiple of sectors, otherwise VirtualBox complains. 155 | (align 512) 156 | 157 | kernel-virtual-end 158 | 159 | ;; This is the physical address of the end of the kernel. 160 | (equ kernel-physical-end 161 | (+ kernel-before-relocation 162 | (- kernel-virtual-end kernel-virtual-start))) 163 | )) 164 | -------------------------------------------------------------------------------- /cc/keyboard.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Keyboard handling mode functions. 6 | ;;;; BIOS interruptions are not used. 7 | ;;;; License: 8 | ;;;; GNU General Public License v2 9 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 10 | ;;;; Copyright (C) 2015-2018 Yujian Zhang 11 | 12 | (in-package :cc) 13 | 14 | (defparameter *keyboard-constants* 15 | `( 16 | ;;; Keyboard related constants. Note that input and output are 17 | ;;; from keyboard's perspective, not from user/cpu's persepctive. 18 | (equ kbd-encoder-buf #x60) 19 | (equ kbd-encoder-cmd-reg #x60) 20 | (equ kbd-ctrl-status-reg #x64) 21 | (equ kbd-ctrl-cmd-reg #x64) 22 | (equ kbd-ctrl-status-mask-out-buf #x01) 23 | (equ kbd-ctrl-status-mask-in-buf #x02) 24 | (equ kbd-ctrl-status-mask-system #x04) 25 | (equ kbd-ctrl-status-mask-cmd-data #x08) 26 | (equ kbd-ctrl-status-mask-locked #x10) 27 | (equ kbd-ctrl-status-mask-aux-buf #x20) 28 | (equ kbd-ctrl-status-mask-timeout #x40) 29 | (equ kbd-ctrl-status-mask-parity #x80) 30 | (equ kbd-ctrl-cmd-disable-keyboard #xad) 31 | (equ kbd-ctrl-cmd-enable-keyboard #xae) 32 | (equ kbd-ctrl-cmd-read-output-port #xd0) 33 | (equ kbd-ctrl-cmd-write-output-port #xd1) 34 | (equ kbd-ctrl-cmd-enable-a20 #xdd) 35 | (equ kbd-ctrl-cmd-system-reset #xfe) 36 | (equ kbd-encoder-cmd-set-led #xed) 37 | (equ kbd-encoder-cmd-set-led-capslock-on #x4) 38 | (equ kbd-encoder-cmd-set-led-capslock-off #x0) 39 | (equ kbd-encoder-cmd-set-scan-code #xf0) 40 | (equ kbd-encoder-cmd-set-scan-code-1 #x1) 41 | (equ kbd-encoder-cmd-enable-scanning #xf4) 42 | (equ kbd-encoder-cmd-disable-scanning #xf5) 43 | (equ kbd-encoder-cmd-reset #xff) 44 | ;; Codes for key states and toggle stages. Defined by internal usage only. 45 | (equ kbd-left-shift #x80) 46 | (equ kbd-right-shift #x81) 47 | (equ kbd-left-ctrl #x82) 48 | (equ kbd-right-ctrl #x83) 49 | (equ kbd-left-alt #x84) 50 | (equ kbd-right-alt #x85) 51 | (equ kbd-capslock #x86) 52 | (equ kbd-numlock #x87) 53 | (equ kbd-ascii-a #x61) 54 | (equ kbd-ascii-q #x71) 55 | (equ kbd-ascii-z #x7a) 56 | ;; Test whether key is released or not. If highest bit is 1, then key 57 | ;; is released; otherwise pressed. 58 | (equ kbd-key-released-mask #x80) 59 | ;; Reset the highest bit (indicating key is released or not) to 0. 60 | ;; kbd-scancode-mask is 1's complement of kbd-key-released-mask 61 | (equ kbd-scancode-mask #x7f) 62 | )) 63 | 64 | (defparameter *keyboard-16* 65 | ;;; 16-bit keyboard code related to A20 enabling. 66 | `(;;; The following 4 functions are exactly same (except the label 67 | ;;; names) as those functions without -16 suffix, defined in 68 | ;;; *keyboard*. Function descriptions are not shown here. 69 | 70 | kbd-ctrl-send-cmd-16 71 | (mov bl al) ; Save AL 72 | (call wait-kbd-in-buf-16) 73 | (mov al bl) 74 | (out kbd-ctrl-cmd-reg al) 75 | (ret) 76 | 77 | kbd-encoder-send-cmd-16 78 | (mov bl al) ; Save AL 79 | (call wait-kbd-in-buf-16) 80 | (mov al bl) 81 | (out kbd-encoder-cmd-reg al) 82 | (ret) 83 | 84 | wait-kbd-in-buf-16 85 | (in al kbd-ctrl-status-reg) ; Get status 86 | (test al kbd-ctrl-status-mask-in-buf) 87 | (jnz wait-kbd-in-buf-16) 88 | (ret) 89 | 90 | wait-kbd-out-buf-16 91 | (in al kbd-ctrl-status-reg) ; Get status 92 | (test al kbd-ctrl-status-mask-out-buf) 93 | (jz wait-kbd-out-buf-16) 94 | (ret) 95 | )) 96 | 97 | (defparameter *keyboard* 98 | `( 99 | ;;; Initialize keyboard by set scan code set 1. 100 | ;;; Input: None 101 | ;;; Output: None 102 | ,@(def-fun 'init-keyboard nil 103 | `( 104 | ;; TODO: double check whether to use encoder-cmd or ctrl-cmd. 105 | ;; TODO: Enable init-keyboard in kernel. 106 | (mov dil kbd-encoder-cmd-reset) 107 | ,@(call-function 'kbd-encoder-send-cmd) 108 | (mov dil kbd-encoder-cmd-disable-scanning) 109 | ,@(call-function 'kbd-encoder-send-cmd) 110 | (mov dil kbd-encoder-cmd-set-scan-code) 111 | ,@(call-function 'kbd-encoder-send-cmd) 112 | (mov dil kbd-encoder-cmd-set-scan-code-1) 113 | ,@(call-function 'kbd-encoder-send-cmd) 114 | (mov dil kbd-encoder-cmd-enable-scanning) 115 | ,@(call-function 'kbd-encoder-send-cmd))) 116 | 117 | ;;; Turn on CapsLock LED. 118 | ;;; Input: None 119 | ;;; Output: None 120 | ,@(def-fun 'turn-on-capslock-led nil 121 | `( 122 | (mov dil kbd-encoder-cmd-set-led) 123 | ,@(call-function 'kbd-encoder-send-cmd) 124 | (mov dil kbd-encoder-cmd-set-led-capslock-on) 125 | ,@(call-function 'kbd-encoder-send-cmd) 126 | )) 127 | 128 | 129 | ;;; Send command byte to keyboard controller. 130 | ;;; Input: 131 | ;;; AL: command byte 132 | ;;; Output: None 133 | ;;; Modified registers: BL 134 | ,@(def-fun 'kbd-ctrl-send-cmd nil 135 | `( 136 | ,@(call-function 'wait-kbd-in-buf) 137 | (mov al dil) 138 | (out kbd-ctrl-cmd-reg al))) 139 | 140 | ;;; Send command byte to keyboard encoder. 141 | ;;; Input: 142 | ;;; DIL: command byte 143 | ;;; Output: None 144 | ;;; Modified registers: AL 145 | ,@(def-fun 'kbd-encoder-send-cmd nil 146 | `( 147 | ,@(call-function 'wait-kbd-in-buf) 148 | (mov al dil) 149 | (out kbd-encoder-cmd-reg al))) 150 | 151 | ;;; Wait until the keyboard controller input buffer empty, 152 | ;;; therefore command can be written 153 | ;;; Input: None 154 | ;;; Output: None 155 | ;;; Modified registers: AL 156 | ,@(def-fun 'wait-kbd-in-buf nil 157 | `( 158 | (in al kbd-ctrl-status-reg) ; Get status 159 | (test al kbd-ctrl-status-mask-in-buf) 160 | (jnz wait-kbd-in-buf))) 161 | 162 | ;;; Wait until the keyboard controller output buffer ready for 163 | ;;; reading. 164 | ;;; Input: None 165 | ;;; Output: None 166 | ;;; Modified registers: AL 167 | ,@(def-fun 'wait-kbd-out-buf nil 168 | `( 169 | (in al kbd-ctrl-status-reg) ; Get status 170 | (test al kbd-ctrl-status-mask-out-buf) 171 | (jz wait-kbd-out-buf))) 172 | 173 | ;;; Function getchar. Get keystroke from keyboard without echo. If 174 | ;;; keystroke is available, it is removed from keyboard buffer. 175 | ;;; Use polling method. TODO: use interrupt. 176 | ;;; So far only a few keys are scanned. TODO: support full set of scan code. 177 | ;;; TODO: handle key repetition. 178 | ;;; Input: None 179 | ;;; Output: 180 | ;;; AL: ASCII character (0 indicats a key is released or not handled) 181 | ;;; Modified registers: RSI, RDX 182 | ,@(def-fun 'getchar nil 183 | `( 184 | ,@(call-function 'wait-kbd-out-buf) 185 | (xor eax eax) 186 | ;; Use DL to store whether key is released or pressed. 187 | ;; Zero: key is pressed; otherwise released. 188 | (xor edx edx) 189 | (in al kbd-encoder-buf) ; Get key data 190 | (mov dl al) 191 | ;; After following instruction, DL stores whether key is released (#x80) 192 | ;; or pressed (#x0). 193 | (and dl kbd-key-released-mask) 194 | (and al kbd-scancode-mask) 195 | ;; Now highest bit of AL is 0, and we can index into scan code set table. 196 | (mov rsi scan-code-set-1) 197 | (add rsi rax) 198 | (lodsb) 199 | (cmp al kbd-left-shift) 200 | ;; kbd-left-shift is the first code for key and toggle states. 201 | (jb near .shutdown-check) 202 | (jnz .check-right-shift) 203 | (test dl dl) 204 | (setz (kbd-left-shift-status)) 205 | (jmp short .set-shift-status) 206 | .check-right-shift 207 | (cmp al kbd-right-shift) 208 | (jnz .check-capslock) 209 | (test dl dl) 210 | (setz (kbd-right-shift-status)) 211 | (jmp short .set-shift-status) 212 | .check-capslock 213 | (cmp al kbd-capslock) 214 | (jnz .check-left-ctrl) 215 | (test dl dl) 216 | ;; Ignore the release of Capslock key. 217 | (jnz near .clear-key) 218 | ;; Toggle kbd-capslock-status between 0 and 1. 219 | (xor byte (kbd-capslock-status) 1) 220 | ;; We don't call function `turn-on-capslock-led' since at 221 | ;; least in QEMU, it seems that even if guest OS does 222 | ;; nothing, Capslock LED is automatically adjusted. 223 | ;; Note: in host, if Capslock and Left Ctrl are swapped in file ~/.Xmodmap, 224 | ;; Bochs respects the change, while QEMU and VirtualBox still only recognize 225 | ;; old Capslock. 226 | .set-shift-status 227 | ;; Use DH to store the overall Shift status. 228 | (mov dh (kbd-left-shift-status)) 229 | (or dh (kbd-right-shift-status)) 230 | (mov (kbd-shift-status) dh) 231 | (xor dh (kbd-capslock-status)) 232 | (mov (kbd-to-upper-status) dh) 233 | (jmp near .clear-key) 234 | .check-left-ctrl 235 | (cmp al kbd-left-ctrl) 236 | (jnz .check-right-ctrl) 237 | (test dl dl) 238 | (setz (kbd-left-ctrl-status)) 239 | (jmp short .set-ctrl-status) 240 | .check-right-ctrl 241 | (cmp al kbd-right-ctrl) 242 | (jnz .check-left-alt) 243 | (test dl dl) 244 | (setz (kbd-right-ctrl-status)) 245 | .set-ctrl-status 246 | ;; Use DH to store the overall Ctrl status. 247 | (mov dh (kbd-left-ctrl-status)) 248 | (or dh (kbd-right-ctrl-status)) 249 | (mov (kbd-ctrl-status) dh) 250 | (jmp near .clear-key) 251 | .check-left-alt 252 | (cmp al kbd-left-alt) 253 | (jnz .check-right-alt) 254 | (test dl dl) 255 | (setz (kbd-left-alt-status)) 256 | (jmp short .set-alt-status) 257 | .check-right-alt 258 | (cmp al kbd-right-alt) 259 | (jnz near .clear-key) 260 | (test dl dl) 261 | (setz (kbd-right-alt-status)) 262 | .set-alt-status 263 | ;; Use DH to store the overall Alt status. 264 | (mov dh (kbd-left-alt-status)) 265 | (or dh (kbd-right-alt-status)) 266 | (mov (kbd-alt-status) dh) 267 | (jmp near .clear-key) 268 | .shutdown-check 269 | ;; For BOCHS only. Check whether Ctrl-Alt-q is pressed. 270 | (mov dh (kbd-ctrl-status)) 271 | (and dh (kbd-alt-status)) 272 | (test dh dh) 273 | (jz .translate-check) 274 | (cmp al kbd-ascii-q) 275 | (jnz .translate-check) 276 | ,@(call-function 'bochs-shutdown) 277 | ;; The computer should have been shutdown already. Just for completeness. 278 | (jmp short .done) 279 | .translate-check 280 | ;; For alphabetic characters (a-z), check kbd-to-upper-status (i.e. 281 | ;; both Shift and Capslock are checked). Note that we don't check A-Z 282 | ;; since table scan-code-set-1 only generates a-z. 283 | (cmp al kbd-ascii-a) 284 | (jb .non-alphabetic-characters) 285 | (cmp al kbd-ascii-z) 286 | (ja .non-alphabetic-characters) 287 | .alphabetic-characters 288 | (mov dh (kbd-to-upper-status)) 289 | (test dh dh) 290 | (jz .test-key-release) ; Translation not needed. 291 | (jmp short .translate) 292 | .non-alphabetic-characters 293 | (mov dh (kbd-shift-status)) 294 | (test dh dh) 295 | (jz .test-key-release) ; Translation not needed. 296 | .translate 297 | ;; Shift has been pressed 298 | (mov rsi lower-to-upper-table) 299 | (add rsi rax) 300 | (lodsb) 301 | .test-key-release 302 | (test dl dl) 303 | (jnz .done) 304 | .clear-key 305 | ;; Set AL to 0 if highest bit of DL is 1 as we don't handle key release for now. 306 | ;; Also set AL to 0 if keys for states and toggles are pressed/released. 307 | (xor eax eax) 308 | .done)) 309 | 310 | ;; Left Shift status: 0: released; 1: pressed 311 | kbd-left-shift-status (db 0) 312 | ;; Right Shift status: 0: released; 1: pressed 313 | kbd-right-shift-status (db 0) 314 | ;; Overall Shift status is 0 if all shift key are released else 1 315 | ;; (i.e. if any of the Shift key is pressed). Note that for 316 | ;; non-alphabetic characters, only kbd-shift-status matters (i.e. 317 | ;; kbd-capslock-status does not have any influence). 318 | kbd-shift-status (db 0) 319 | ;; Capslock status: 0: off; 1: on. Note that different from Shift/Ctrl/Alt, 320 | ;; Capslock is a toggle when Capslock key is pressed. Release of Capslock key 321 | ;; is ignored. 322 | kbd-capslock-status (db 0) 323 | ;; Overall status of whether to translate characters from lower 324 | ;; case (including punctuations) to upper case. The Shift status 325 | ;; (kbd-shift-status) is XORed with Capslock status 326 | ;; (kbd-capslock-status) to determine whether lower-to-upper table 327 | ;; below should be used (if the XOR result is 1) for alphabetic 328 | ;; characters or not. 329 | kbd-to-upper-status (db 0) 330 | ;; Left Ctrl status: 0: released; 1: pressed 331 | kbd-left-ctrl-status (db 0) 332 | ;; Right Ctrl status: 0: released; 1: pressed 333 | kbd-right-ctrl-status (db 0) 334 | ;; Overall Ctrl status is 0 if all ctrl key are released else 1 335 | ;; (i.e. if any of the Ctrl key is pressed). 336 | kbd-ctrl-status (db 0) 337 | ;; Left Alt status: 0: released; 1: pressed 338 | kbd-left-alt-status (db 0) 339 | ;; Right Alt status: 0: released; 1: pressed 340 | kbd-right-alt-status (db 0) 341 | ;; Overall Alt status is 0 if all alt key are released else 1 342 | ;; (i.e. if any of the Alt key is pressed). 343 | kbd-alt-status (db 0) 344 | ;;; Table for Scan code set 1: http://wiki.osdev.org/Keyboard#Scan_Code_Set_1 345 | ;;; Release code is not stored as it is simply the sum of pressed code and #x80 346 | ;;; (as in http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html#ss1.1) 347 | ;;; TODO: add right control and right shift. 348 | scan-code-set-1 349 | (db 0 27 49 50 51 52 53 54 55 56 57 48 45 61 8 9 350 | 113 119 101 114 116 121 117 105 111 112 91 93 10 kbd-left-ctrl 97 115 351 | 100 102 103 104 106 107 108 59 39 96 kbd-left-shift 92 122 120 99 118 352 | 98 110 109 44 46 47 kbd-right-shift 0 kbd-left-alt 32 kbd-capslock 0 0 0 0 0 353 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 354 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 355 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 356 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 357 | ) 358 | 359 | ;;; Convert from lower case ASCII (index) to upper case ASCII (value) 360 | ;;; from https://en.wikipedia.org/wiki/ASCII#Character_set 361 | ;;; An example: index 0x30 is the ASCII code for '0', and the corresponding 362 | ;;; value is 0x29 (41 in decimal), which is the ASCII code for 363 | ;;; ')'. This corresponds to the relationship that ')' is the 364 | ;;; character when both Shift and '0' is pressed. 365 | lower-to-upper-table 366 | (db 0 0 0 0 0 0 0 0 8 9 10 0 0 0 0 0 367 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 368 | 32 0 0 0 0 0 0 34 0 0 0 0 60 95 62 63 369 | 41 33 64 35 36 37 94 38 42 40 0 58 0 43 0 0 370 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 371 | 0 0 0 0 0 0 0 0 0 0 0 123 124 125 0 0 372 | 126 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 373 | 80 81 82 83 84 85 86 87 88 89 90 0 0 0 0 0) 374 | )) 375 | -------------------------------------------------------------------------------- /cc/lnasdf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Create symbolic link of CC system for ASDF. 3 | mkdir -p ~/common-lisp 4 | ln -fs `pwd`\/cc.asd ~/common-lisp/cc.asd 5 | -------------------------------------------------------------------------------- /cc/memory.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Memory management. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2015 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defparameter *memory-16* 14 | `( 15 | ;;; http://wiki.osdev.org/Detecting_Memory_(x86) 16 | ;;; http://www.brokenthorn.com/Resources/OSDev17.html 17 | 18 | ;;; Use INT 0x15, EAX=#xe820 BIOS function to get memory map. 19 | ;;; Modified registers: all registers are trashed except ESI. 20 | get-memory-map 21 | ;; String "SMAP". 22 | (equ mm-smap #x0534D4150) 23 | (equ mm-entry-size 24) 24 | (equ mm-start-addr 0) 25 | ;; Offset for the end address. Note that it is the length field after 26 | ;; the BIOS call, but the value is replaced with end address by this function. 27 | (equ mm-end-addr 8) 28 | (equ mm-memory-type 16) 29 | (equ mm-entries-offset 2) 30 | ;; Stores Number of memory map entries. This is the linear address. 31 | ;; Corresponding semgnet:offset is in mm-count-physical-segment 32 | ;; and mm-count-physical-offset 33 | (equ mm-count-physical-addr #x80000) 34 | ;; The following is the pair of segment:offset 35 | (equ mm-count-physical-segment (ash mm-count-physical-addr -4)) 36 | (equ mm-count-physical-offset (logand mm-count-physical-addr #xffff)) 37 | ;; Maximum number of entries. 38 | (equ mm-entry-max 20) 39 | ;; Starting address of the memory map entries. This is the linear address. 40 | ;; Corresponding semgent and offset is mm-count-physical-segment, and 41 | ;; mm-entries-physical-offset. 42 | (equ mm-entries-physical-addr (+ mm-count-physical-addr mm-entries-offset)) 43 | (equ mm-entries-physical-offset (logand mm-entries-physical-addr #xffff)) 44 | (push es) 45 | (mov ax mm-count-physical-segment) 46 | (mov es ax) 47 | (xor ebx ebx) ; Set EBX to 0 to start 48 | (mov di mm-entries-physical-offset) 49 | (xor bp bp) 50 | (mov edx mm-smap) ; Place "SMAP" into edx 51 | (mov eax #xe820) 52 | (es mov dword (di 20) 1) ; Force a valid ACPI 3.x entry 53 | (mov ecx mm-entry-size) 54 | (int #x15) 55 | (jc .fail) ; CF is set if the BIO function is not supported. 56 | (mov edx mm-smap) ; Some BIOSes may trash this register. 57 | (cmp eax edx) ; On success, EAX must have been rest to "SMAP" 58 | (jne .fail) 59 | (test ebx ebx) ; EBX = 0 implies that the list contains only 1 entry. 60 | (je .fail) 61 | (jmp short .jump-in) 62 | .loop 63 | (mov eax #xe820) ; EAX, ECX get trashed on every int #x15 call. 64 | (es mov dword (di 20) 1) ; Force a valid ACPI 3.x entry 65 | (mov ecx mm-entry-size) 66 | (int #x15) 67 | (jc .done) ; CF means the end of list. 68 | (mov edx mm-smap) ; Repair potentially trashed register. 69 | .jump-in 70 | (jcxz .skip-entry) ; Skip and 0 length entry. 71 | (cmp cl 20) ; Got a 24 byte ACPI 3.x response? 72 | (jbe .no-text) 73 | (es test byte (di 20) 1) ; Test whether the "ignore this data" bit is clear or not. 74 | (je .skip-entry) 75 | .no-text 76 | (es mov ecx (di 8)) ; Get lower 32 bit of memory region length. 77 | (es or ecx (di 12)) ; "Or" it with upper 32 bit to test for zero. 78 | (jz .skip-entry) 79 | ;; Got a good entry. Modify 64 bit length field into end address. 80 | ;; Subtract 1 from length. 81 | (es dec dword (di 8)) 82 | (es sbb dword (di 12) 0) 83 | ;; Then add base. 84 | (es mov eax (di)) 85 | (es add (di 8) eax) 86 | (es mov eax (di 4)) 87 | (es adc (di 12) eax) 88 | (inc bp) ; Increase entry count 89 | (add di mm-entry-size) ; Move to next entry. 90 | .skip-entry 91 | (test ebx ebx) ; If EBX is reset to 0, the list is complete. 92 | (jne .loop) 93 | (cmp bp mm-entry-max) ; If the actual memory count exceeds the limit, 94 | ; Memory data will be trashed by page tables. 95 | (jae .fail) 96 | .done 97 | (es mov (mm-count-physical-offset) bp) 98 | (clc) ; Clear CF (since .done lable is entered after "jc" instruction). 99 | (pop es) 100 | (ret) 101 | .fail 102 | (mov si .mm-error-message) 103 | (call println-16) 104 | .panic 105 | (hlt) 106 | (jmp short .panic) 107 | .mm-error-message (db "ERROR: memory map cannot be detected." 0) 108 | )) 109 | 110 | (defparameter *memory-32* 111 | `( 112 | ;;; Memory type constants. 113 | (equ memory-usable 1) 114 | (equ memory-reserved 2) 115 | (equ memory-acpi-reclaimable 3) 116 | (equ memory-acpi-nvs 4) 117 | (equ memory-bad 5) 118 | 119 | ;;; Get the maximum physical memory size, in bytes. Return the result in (EDX, EAX), 120 | ;;; where EDX stores the upper 32 bits. 121 | ;;; This is based on memory map detected with get-memory-map. 122 | ;;; TODO: for 32 bit operation, we don't need to get memory size as virtual 123 | ;;; memory management will be done in 64 bit mode. For page setup, we only map the 1st 2 MB for kernel 124 | ;;; will be sufficient. Code this function in 64 bit mode will be much easier 125 | ;;; as we can easily handle 64 bit arithmetic in 64 bit mode. 126 | get-memory-size 127 | (push esi) 128 | (push ecx) 129 | (push ebx) 130 | (push ebp) 131 | (movzx ecx word (mm-count-physical-addr)) ; Number of entries to process 132 | (mov esi mm-entries-physical-addr) 133 | (xor edx edx) ; EDX:EAX store the maximum physical address. 134 | (xor eax eax) 135 | .start 136 | (mov ebp (esi mm-memory-type)) 137 | (cmp ebp memory-usable) ; TODO: consider ACPI reclaimable? 138 | (jnz .skip-entry) 139 | (mov ebp (esi 8)) ; Lower 32 bits. 140 | (mov ebx (esi 12)) ; Higher 32 bits. Now EBX:EBP store the current physical address. 141 | (cmp ebx edx) 142 | (jb .skip-entry) 143 | (ja .update) 144 | (cmp ebp eax) 145 | (jbe .skip-entry) 146 | .update 147 | (mov edx ebx) 148 | (mov eax ebp) 149 | .skip-entry 150 | (add esi mm-entry-size) 151 | (loop .start) 152 | .done 153 | (pop ebp) 154 | (pop ebx) 155 | (pop ecx) 156 | (pop esi) 157 | (ret) 158 | )) 159 | 160 | (defparameter *memory* 161 | `(;;; ==================== Start of Physical Memory Manager (PMM) ==================== 162 | (equ page-size-shift 21) ; Shift for 2 MB 163 | (equ mm-count-virtual-addr (+ kernel-virtual-base mm-count-physical-addr)) 164 | (equ mm-entries-virtual-addr (+ kernel-virtual-base mm-entries-physical-addr)) 165 | 166 | ;;; Function pmm-init: initilize the pmm. 167 | ;;; Input: None 168 | ;;; Output: None 169 | ;;; 170 | ;;; Algorithm: 171 | ;;; First we mark all page frames as free (set corresponding bit to 0). 172 | ;;; Then we goes through the memory map. 173 | ;;; For every memory entry unusable: 174 | ;;; For every page frame whose starting address <= end address of the memory entry: 175 | ;;; If the end address of the page frame >= the starting address of the memory entry: 176 | ;;; Mark the page frame as used (set the bit to 1). 177 | ,@(def-fun 'pmm-init nil 178 | `( 179 | ;; First initialize page-table-bitmap. 180 | (mov rdi page-table-bitmap-virtual-addr) 181 | (mov rsi page-table-max) 182 | (push rdi) 183 | ,@(call-function 'bitmap-init) 184 | (pop rdi) 185 | ;; The first three page tables are already used. Note that identity mapping tables 186 | ;; are available for reuse. 187 | (xor esi esi) 188 | ,@(call-function 'bitmap-set) 189 | (mov esi 1) 190 | ,@(call-function 'bitmap-set) 191 | (mov esi 2) 192 | ,@(call-function 'bitmap-set) 193 | ;; Now initialize page-frame-bitmap. 194 | (mov rsi (memory-size-virtual-addr)) 195 | (mov eax 1) 196 | (shl eax page-size-shift) 197 | (dec eax) 198 | (add rsi rax) 199 | (shr rsi page-size-shift) ; Get ceil(memory-size / (2 ^ page-size-shift)) 200 | (mov rdi page-frame-bitmap-virtual-addr) 201 | (push rdi) 202 | ,@(call-function 'bitmap-init) 203 | (pop rdi) 204 | ;; Now loop throught every unusable memory entry. 205 | (movzx ecx word (mm-count-virtual-addr)) ; Number of entries to process 206 | (mov rax mm-entries-virtual-addr) ; Use RAX to loop throught memory map entry. 207 | .memory-entry 208 | (mov edx (rax mm-memory-type)) 209 | (cmp edx memory-usable) ; TODO: consider ACPI reclaimable? 210 | (je .skip-entry) 211 | (mov r8 (rax mm-start-addr)) 212 | (mov r9 (rax mm-end-addr)) 213 | (xor r10d r10d) ; The index to the page frames. 214 | .page-frame 215 | (mov r11 r10) 216 | (shl r11 page-size-shift) ; Starting address of the page frame. 217 | (cmp r11 r9) 218 | ;; Skip the current and remaining page frames, as the memory entry cannot 219 | ;; overlap with them. 220 | (ja .skip-entry) 221 | (mov r11 r10) 222 | (inc r11) 223 | (shl r11 page-size-shift) ; End address of the page frame. 224 | (cmp r11 r8) 225 | (jb .next-page-frame) 226 | ;; Now the unusable memory entry overlaps with the page frame, so 227 | ;; we set it to used (bit is 1). 228 | (push rsi) 229 | (push rdx) 230 | (mov rsi r10) 231 | ,@(call-function 'bitmap-set) 232 | (pop rdx) 233 | (pop rsi) 234 | .next-page-frame 235 | (inc r10) 236 | (cmp r10 rsi) 237 | (jb .page-frame) 238 | .skip-entry 239 | (add rax mm-entry-size) 240 | (loop .memory-entry) 241 | )) 242 | 243 | ;;; Function pmm-alloc-page-frame: allocate one page frame. 244 | ;;; Input: None. 245 | ;;; Output: 246 | ;;; RAX: starting physical address of the page frame. 247 | ;;; 0 if out of memory. 248 | ,@(def-fun 'pmm-alloc-page-frame nil 249 | `( 250 | (mov rdi page-frame-bitmap-virtual-addr) 251 | ,@(call-function 'bitmap-scan) 252 | (mov rsi -1) 253 | (cmp rax rsi) 254 | (je .out-of-memory) 255 | (mov rsi rax) 256 | (push rax) 257 | ,@(call-function 'bitmap-set) 258 | (pop rax) 259 | (shl rax page-size-shift) 260 | (jmp short .done) 261 | .out-of-memory 262 | (xor eax eax) 263 | .done 264 | )) 265 | 266 | ;;; Function pmm-free-page-frame: free one page frame. 267 | ;;; Input: 268 | ;;; RDI: starting physical address of the page frame. 269 | ;;; Output: None. 270 | ,@(def-fun 'pmm-free-page-frame nil 271 | `( 272 | (mov rsi rdi) 273 | (shr rsi page-size-shift) 274 | (mov rdi page-frame-bitmap-virtual-addr) 275 | ,@(call-function 'bitmap-unset))) 276 | 277 | ;;; ===================== End of Physical Memory Manager (PMM) ===================== 278 | )) 279 | -------------------------------------------------------------------------------- /cc/misc.asm: -------------------------------------------------------------------------------- 1 | ;; NASM code for cross check the assembly output from test-cc.lisp. 2 | ;; The test is performed as follows: 3 | ;; 1. Run NASM with: /usr/local/bin/nasm -o misc.img misc.asm 4 | ;; 2. In CL REPL, compare the output with (equal (read-image "misc.img") (asm *misc-asm*)) 5 | ;; Note that above nasm command assumes the usage of nasm installed from brew. 6 | 7 | org 7C00h 8 | bits 16 9 | 10 | start: 11 | align 4 12 | bt edx, 29 13 | align 4 14 | btc eax, 28 15 | btr ebx, 27 16 | bts ecx, 26 17 | call msg 18 | clc 19 | cld 20 | cli 21 | 22 | hlt 23 | in al, 3 24 | in ax, 4 25 | in al, dx 26 | in ax, dx 27 | int3 28 | int 10h 29 | .loop: 30 | jcxz .loop 31 | je .loop 32 | jmp short .loop 33 | jmp near meta_msg 34 | lgdt [msg] 35 | lidt [msg] 36 | lldt dx 37 | lldt [msg] 38 | lodsb 39 | lodsw 40 | lodsd 41 | loop .loop 42 | mov bl, byte [es:di] 43 | mov byte [ds:si], 0ffh 44 | mov ah, 9 45 | mov bl, [msg] 46 | mov [msg], bh 47 | mov bx, endmsg - msg 48 | mov ax, cx 49 | mov [msg], bx 50 | mov cx, [1c7bh] 51 | mov byte [msg], 42 52 | mov word [msg], 123 53 | mov es, bx 54 | mov ax, cs 55 | mov cr0, eax 56 | mov eax, cr0 57 | movzx ax, byte [msg] 58 | movzx edx, cx 59 | movzx eax, byte [msg] 60 | movzx eax, word [msg] 61 | 62 | nop 63 | out 3, al 64 | out 4, ax 65 | out dx, al 66 | out dx, ax 67 | push cx 68 | push edx 69 | push cs 70 | push ss 71 | push ds 72 | push es 73 | pushf 74 | pushfd 75 | pop dx 76 | pop ecx 77 | pop ss 78 | pop ds 79 | pop es 80 | popf 81 | popfd 82 | rdmsr 83 | rep movsb 84 | rep movsw 85 | rep movsd 86 | ret 87 | stc 88 | std 89 | sti 90 | stosb 91 | stosw 92 | stosd 93 | wrmsr 94 | 95 | bits 64 96 | default rel 97 | bsf ax, bx 98 | bsf ecx, edx 99 | bsf r10, [msg] 100 | bsr ax, r8w 101 | bsr r10d, r9d 102 | bsr rax, r12 103 | bswap ebx 104 | bswap rax 105 | bswap r10 106 | bt edx, 29 107 | bt edx, ecx 108 | bt rdx, 30 109 | bt rax, rbx 110 | btc rax, 29 111 | btr rbx, 28 112 | bts rcx, 27 113 | call msg 114 | cmova ax, bx 115 | cmovc eax, edx 116 | cmove rdx, r10 117 | cmpxchg cl, dl 118 | cmpxchg cx, dx 119 | cmpxchg edi, edx 120 | cmpxchg rcx, r10 121 | cmpxchg8b [rbx] 122 | cmpxchg16b [rbx] 123 | invlpg [abs 0] 124 | iretq 125 | jb near msg 126 | jmp rbx 127 | jmp msg 128 | jmp [msg] 129 | leave 130 | lgdt [msg] 131 | lidt [msg] 132 | lodsq 133 | mov eax, 1234h 134 | mov rsp, 90000h 135 | mov rax, 1122334455667788h 136 | mov rcx, [msg] 137 | mov rcx, [abs msg] 138 | mov rdi, [abs 0b8000h] 139 | mov rbx, rcx 140 | mov rax, -1 141 | mov qword [msg], 1019 142 | mov ax, r8w 143 | mov r9w, word [fs: rel msg] 144 | mov dil, 19 145 | movsq 146 | movzx r10, al 147 | movzx eax, byte [msg] 148 | movzx rdx, word [msg] 149 | push r10 150 | pushfq 151 | pop rax 152 | popcnt r11, [msg] 153 | popfq 154 | sal ebx, 1 155 | sar edx, cl 156 | seta ah 157 | setz byte [msg] 158 | shl r10, 6 159 | shr qword [msg], 8 160 | rep stosq 161 | syscall 162 | sysret 163 | xadd cl, dl 164 | xadd cx, dx 165 | xadd edi, edx 166 | xadd rcx, r10 167 | xchg ax, bx 168 | xchg cx, ax 169 | xchg eax, ebx 170 | xchg ecx, eax 171 | xchg rax, rbx 172 | xchg rcx, rax 173 | xchg cl, al 174 | xchg bx, cx 175 | xchg ebx, edx 176 | xchg r15, r10 177 | 178 | jecxz msg 179 | jrcxz msg 180 | 181 | hi equ 4 182 | meta_msg: 183 | dw msg 184 | resb 4 185 | msg: 186 | db "Hello World! " 187 | endmsg: 188 | times 3 db 0 189 | dw 0AA55h 190 | resw 3 191 | dd 123456,7891011 192 | resd 2 193 | dq 3372036854775808 194 | resq 1 195 | -------------------------------------------------------------------------------- /cc/nasm.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; NASM related functions. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2012 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defun ->nasm(listing) 14 | "Return a string of NASM code translated from LISTING (as the input to (ASM))." 15 | (let ((fstr (make-array '(0) :element-type 'base-char 16 | :fill-pointer 0 :adjustable t))) 17 | (with-output-to-string (s fstr) 18 | (dolist (e listing (string-downcase fstr)) 19 | (cond ((atom e) (format s "~A:~%" e)) 20 | ((member (first e) '(db dw dd dq)) 21 | (format s "~A:~% ~A \"~A\"~%" (second e) (first e) (third e))) 22 | ((eql (first e) 'mov) 23 | (format s " mov ") 24 | (format-addr s (second e)) 25 | (format s ", ") 26 | (format-addr s (third e)) 27 | (format s "~%")) 28 | (t (format s " ~A ~{~A~^,~}~%" (car e) (cdr e)))))))) 29 | 30 | (defun format-addr (stream expr) 31 | "Format address related expressions e.g. in MOV." 32 | (if (atom expr) 33 | (format stream "~A" expr) 34 | (format stream "[~{~A~^+~}]" expr))) 35 | 36 | (deftest test-nasm () 37 | (check 38 | (string= (->nasm 39 | '((org #x7c00) 40 | (bits 16) 41 | (mov (bp) es) 42 | (mov (bx si) ds) 43 | (mov (32330) ds) 44 | (mov (msg) ds) 45 | (mov (bx) cs) 46 | (mov (bx si 1) ds) 47 | (mov ds (bx si 1001)) 48 | (bits 32) 49 | (mov (ebp) ebx) 50 | (mov (123456) edx) 51 | (mov (eax) edx) 52 | (mov (ebp 36) ecx) 53 | (mov (esp #x23) ebx) 54 | (mov (eax*2 esi) edx) 55 | (mov (esi*2 ebp 123) edx) 56 | (db msg "Hello World!") 57 | endmsg)) 58 | (concatenate 59 | 'string 60 | " org 31744" 61 | " bits 16" 62 | " mov [bp], es" 63 | " mov [bx+si], ds" 64 | " mov [32330], ds" 65 | " mov [msg], ds" 66 | " mov [bx], cs" 67 | " mov [bx+si+1], ds" 68 | " mov ds, [bx+si+1001]" 69 | " bits 32" 70 | " mov [ebp], ebx" 71 | " mov [123456], edx" 72 | " mov [eax], edx" 73 | " mov [ebp+36], ecx" 74 | " mov [esp+35], ebx" 75 | " mov [eax*2+esi], edx" 76 | " mov [esi*2+ebp+123], edx" 77 | "msg:" 78 | " db \"hello world! \"" 79 | "endmsg:")))) 80 | -------------------------------------------------------------------------------- /cc/package.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Package definition. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2009-2012 Yujian Zhang 10 | 11 | (defpackage #:cc 12 | (:use #:common-lisp) 13 | (:export 14 | #:asm 15 | #:*bootloader* 16 | #:test-cc 17 | #:write-kernel)) 18 | -------------------------------------------------------------------------------- /cc/paging.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Paging functions. 6 | ;;;; References: 7 | ;;;; [1] AMD64 Architecture Programmer's Manual Volume 2: System Programming. 8 | ;;;; Publication No. 24593; Revision: 3.25 9 | ;;;; License: 10 | ;;;; GNU General Public License v2 11 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 12 | ;;;; Copyright (C) 2015 Yujian Zhang 13 | 14 | (in-package :cc) 15 | 16 | (defparameter *paging-32* 17 | `( 18 | ;;; Technical details for 2 MB page translation can be found in 19 | ;;; section 5.3.4 (2-Mbyte Page Translation) of [1]. 20 | ;;; At the beginning, paging setup is based on 21 | ;;; http://wiki.osdev.rg/Entering_Long_Mode_Directly 22 | ;;; 23 | ;;; Setup two mappings: 24 | ;;; 1) Identity mapping for bottom 2 MB physical address. 25 | ;;; 2) Map ALL available physical memory to higher memory space 26 | ;;; starting from -2GB memory space below recursive mapping. As 27 | ;;; recursive mapping occupies 512 GB and starts from #xffffff8000000000, 28 | ;;; kernel starts from #xffffff7f80000000. 29 | ;;; Identity mapping will be removed after entering 64 bit mode 30 | ;;; by calling function unmap-lower-memory. 31 | ;;; 32 | ;;; Suppose PML4 points to address A (`pml4-base` below), then there are 33 | ;;; five 4 KB memory regions to be processed by this function (note that we put 34 | ;;; identity mapping after kernel mapping as identity mapping will be unmapped): 35 | ;;; A .. A + #x0fff: Page Map Level 4 36 | ;;; A + #x1000 .. A + #x3fff: Page Directory Pointer Table for higher half mapping. 37 | ;;; A + #x2000 .. A + #x4fff: Page Directory Table for higher half mapping. 38 | ;;; A + #x3000 .. A + #x1fff: Page Directory Pointer Table for identity mapping. 39 | ;;; A + #x4000 .. A + #x2fff: Page Directory Table for identity mapping. 40 | 41 | setup-paging 42 | 43 | (equ pml4-base #x10000) 44 | (equ page-table-size 4096) ; Number of bytes occupied by a page table. 45 | 46 | ;; Page flags. 47 | (equ page-present (expt 2 0)) 48 | (equ page-writable (expt 2 1)) 49 | (equ page-user-accessible (expt 2 2)) 50 | (equ page-write-through (expt 2 3)) 51 | (equ page-cache-disable (expt 2 4)) 52 | (equ page-accessed (expt 2 5)) 53 | (equ page-dirty (expt 2 6)) 54 | (equ page-pde.ps (expt 2 7)) 55 | (equ page-global (expt 2 8)) 56 | (equ page-no-execuite (expt 2 63)) 57 | (equ page-table-flag (+ page-present page-writable)) 58 | (equ page-entry-flag (+ page-table-flag page-pde.ps)) ; In addition to above flags, set PDE.PS for 2 MB page. 59 | 60 | (equ kernel-virtual-base #xffffff7f80000000) ; Start virtual address for higher half kernel. 61 | 62 | ;; The position to store memory size. 63 | (equ memory-size-physical-addr (+ mm-entries-physical-addr (* mm-entry-max mm-entry-size))) 64 | (equ memory-size-virtual-addr (+ kernel-virtual-base memory-size-physical-addr)) 65 | ;; Maximum number of page tables. 66 | (equ page-table-end-next #x70000) 67 | (equ page-table-max (/ (- page-table-end-next pml4-base) page-table-size)) 68 | (equ page-table-bitmap-virtual-addr (+ memory-size-virtual-addr 8)) ; 8 byte to store memory size. 69 | ;; In the calculation below, first 8 for bitmap-offset, second 8 because 1 bytes contains 8 bits. 70 | (equ page-frame-bitmap-virtual-addr 71 | (+ page-table-bitmap-virtual-addr 8 (ceiling page-table-max 8))) 72 | (push edx) 73 | (push ecx) 74 | (push ebx) 75 | (push edi) 76 | 77 | ;; Firstly check the size of the kernel. When kernel is firstly loaded 78 | ;; (before relocated), the memory map of our code/data below 1 MB is like: 79 | ;; 0 - some BIOS stuff 80 | ;; - kernel (starting from #x7c00) 81 | ;; - page tables (starting from pml4-base) 82 | ;; - FREE 83 | ;; - stack 84 | ;; - memory map (starting from mm-count-physical-addr) 85 | ;; - memory size (starting from memory-size-physical-addr), page table bitmap 86 | ;; and page frame bitmap 87 | ;; - other BIOS stuff 88 | ;; If kernel size is too big, code about page tables will trash 89 | ;; the kernel. So the following check is needed. 90 | ;; TODO: we need to make sure that page tables do not run into the region for 91 | ;; stack and memory map. 92 | (mov edx kernel-physical-end) 93 | (cmp edx pml4-base) 94 | (jb .page-continue) 95 | ;; If code comes to this branch, increase pml4-base appropriately. 96 | .panic 97 | (hlt) 98 | (jmp short .panic) 99 | 100 | .page-continue 101 | (call32 get-memory-size) 102 | ;; Store the memory size. 103 | (mov ecx memory-size-physical-addr) 104 | (mov (ecx) eax) 105 | (mov (ecx 4) edx) 106 | ;; TODO. So far we only handle < 4GB memory. As memory size is in 107 | ;; EDX:EAX, we ignore the value in EDX for now. Use EDX to store 108 | ;; the memory size (< 4 GB). 109 | (mov edx eax) 110 | 111 | ;; Zero out the 5 * 4 kB buffer. 112 | (mov edi pml4-base) 113 | (mov ecx #x1400) 114 | (xor eax eax) 115 | (cld) 116 | (rep stosd) 117 | (mov edi pml4-base) 118 | 119 | ;; Build the Page Map Level 4. 120 | ;; First set entry the identity mapping. 121 | (mov eax edi) 122 | (add eax #x3000) ; Address of the Page Directory Pointer Table for identity mapping. 123 | (or eax page-table-flag) 124 | (mov (edi) eax) 125 | ;; Secondly set entry for higher half mapping. 126 | (sub eax #x2000) ; Address of the Page Directory Pointer Table for higher half mapping. 127 | (mov ebx 510) 128 | (mov (ebx*8 edi) eax) 129 | (mov eax 511) ; Now starts recursive mapping. 130 | (shl eax 3) 131 | (add eax edi) 132 | (mov (eax) eax) 133 | 134 | ;; Build the Page Directory Pointer Table for identity mapping. 135 | (mov eax edi) 136 | (add eax #x4000) ; Address of the Page Directory. 137 | (or eax page-table-flag) 138 | (mov (edi #x3000) eax) 139 | 140 | ;; Build the Page Directory Table for identity mapping. Just map 2 MB. 141 | (mov eax page-entry-flag) ; Effectively point EAX to address #x0. 142 | (mov (edi #x4000) eax) 143 | 144 | ;; Build the Page Directory Pointer Table for higher half mapping. 145 | (mov edi (+ pml4-base #x1000)) 146 | (mov eax edi) 147 | (add eax #x1000) ; Address of the Page Directory. 148 | (or eax page-table-flag) 149 | ;; TODO: we only map maximum 1 GB memory now. So we only handle the 2nd last entry here. 150 | (mov ebx 510) ; The second last entry in the 512 entry table. 151 | (mov (ebx*8 edi) eax) 152 | 153 | ;; Build the Page Directory Table for higher half mapping. 154 | (add edi #x1000) 155 | (mov eax page-entry-flag) ; Effectively point EAX to address #x0. 156 | .loop-page-directory-table 157 | (mov (edi) eax) 158 | (add eax #x200000) ; Increase 2 MB. 159 | (add edi 8) 160 | (cmp eax edx) ; Has all memory been mapped? 161 | (jb .loop-page-directory-table) 162 | 163 | (pop edi) 164 | (pop ebx) 165 | (pop ecx) 166 | (pop edx) 167 | 168 | (ret))) 169 | 170 | (defparameter *paging* 171 | `( 172 | ;;; Remove identity mapping of bottom 2 MB. 173 | ,@(def-fun 'unmap-lower-memory nil 174 | `( 175 | (mov rdi pml4-base) 176 | (mov qword (rdi) 0) 177 | (invlpg (abs 0)))) 178 | 179 | ;; Mask to get bits 12-51 from page table entry for the physical address of the frame. 180 | (equ page-frame-mask #x000ffffffffff000) 181 | 182 | ;;; Function pointed-frame. Returns page frame address (physical). 183 | ;;; Input: 184 | ;;; RDI: page table entry address (virtual) 185 | ;;; Output: 186 | ;;; RAX: page frame address. 0 if page table entry is invalid 187 | ;;; (e.g. not present) 188 | ,@(def-fun'pointed-frame nil 189 | `( 190 | (mov rax (rdi)) 191 | (test eax page-present) 192 | (je .not-present) 193 | (mov rsi page-frame-mask) 194 | (and rax rsi) 195 | (jmp short .done) 196 | .not-present 197 | (xor eax eax) 198 | .done)) 199 | 200 | ;;; Function page-directory-entry-set. Return a page directory entry (PDE) given 201 | ;;; the physical frame base address and flags 202 | ;;; Input: 203 | ;;; RDI: page frame base address (should be aligned at 2 MB boundary) and 204 | ;;; smaller than 2^52 (due to x86-64 architecture limitation) 205 | ;;; RSI: page flags 206 | ;;; Output: 207 | ;;; RAX: the page directory entry (PDE). 208 | ;;; Technical details for 2 MB PDE can be found in section 5.3.4 209 | ;;; (2-Mbyte Page Translation) of [1], especially Figure 5-25. "2-Mbyte PDE - Long Mode" 210 | ,@(def-fun 'page-directory-entry-set nil 211 | `( 212 | (equ pde-physical-base-address-mask #xfff00000001fffff) 213 | (mov rdx pde-physical-base-address-mask) 214 | (test rdi rdx) 215 | (jne .panic) 216 | (or rdi rsi) 217 | (mov rax rdi) 218 | (jmp short .done) 219 | .invalid-physical-base-address 220 | .panic 221 | (hlt) 222 | (jmp short .panic) 223 | .done)) 224 | )) 225 | -------------------------------------------------------------------------------- /cc/test-cc.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Regression tests. Cross checked with NASM. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2009-2018 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defun arith-test-1 (mnemonic) 14 | "Return test codes for arithmetic operations: add/and/cmp/or/sub/xor." 15 | `((,mnemonic al 8) 16 | (,mnemonic ax 1000) 17 | (,mnemonic bl 3) 18 | (,mnemonic byte (msg) 4) 19 | (,mnemonic bx 1234) 20 | (,mnemonic word (msg) 5678) 21 | (,mnemonic cx 9) 22 | (,mnemonic word (msg) 12) 23 | (,mnemonic al bl) 24 | (,mnemonic (msg) ch) 25 | (,mnemonic cx bx) 26 | (,mnemonic (msg) dx) 27 | (,mnemonic ch (msg)) 28 | (,mnemonic dx (msg)))) 29 | 30 | (defun arith-test-2 (mnemonic) 31 | "Return test codes for arithmetic operations: div/mul/neg/not" 32 | `((,mnemonic ch) 33 | (,mnemonic byte (msg)) 34 | (,mnemonic di) 35 | (,mnemonic word (bp si 3)))) 36 | 37 | (defun shift-test (mnemonic) 38 | "Return test codes for shift operations: shl/shr." 39 | `((,mnemonic dh 1) 40 | (,mnemonic byte (msg) 1) 41 | (,mnemonic dh cl) 42 | (,mnemonic byte (msg) cl) 43 | (,mnemonic dh 5) 44 | (,mnemonic byte (msg) 5) 45 | (,mnemonic dx 1) 46 | (,mnemonic word (msg) 1) 47 | (,mnemonic dx cl) 48 | (,mnemonic word (msg) cl) 49 | (,mnemonic dx 5) 50 | (,mnemonic word (msg) 5))) 51 | 52 | (defparameter *arith-asm* 53 | `((bits 16) 54 | (org #x7c00) 55 | 56 | ,@(arith-test-1 'add) 57 | ,@(arith-test-1 'and) 58 | ,@(arith-test-1 'cmp) 59 | (dec bx) 60 | (dec eax) 61 | (dec dl) 62 | (dec byte (msg)) 63 | (dec word (bp si 3)) 64 | (dec dword (msg)) 65 | ,@(arith-test-2 'div) 66 | (inc bx) 67 | (inc eax) 68 | (inc dl) 69 | (inc byte (msg)) 70 | (inc word (bp si 3)) 71 | (inc dword (msg)) 72 | ,@(arith-test-2 'mul) 73 | ,@(arith-test-2 'neg) 74 | ,@(arith-test-2 'not) 75 | ,@(arith-test-1 'or) 76 | ,@(shift-test 'shl) 77 | ,@(shift-test 'shr) 78 | ,@(arith-test-1 'sub) 79 | (test al 8) 80 | (test ax 1000) 81 | (test bl 3) 82 | (test byte (msg) 4) 83 | (test bx 1234) 84 | (test (msg) 5678) 85 | (test al bl) 86 | (test (msg) ch) 87 | (test cx bx) 88 | (test (msg) dx) 89 | ,@(arith-test-1 'xor) 90 | 91 | (bits 32) 92 | (add ax 1000) 93 | (dec dx) 94 | (dec ebp) 95 | (inc dx) 96 | (inc ebp) 97 | 98 | (bits 64) 99 | (addressing abs) 100 | (adc rax #x12345) 101 | (add ebx 1000) 102 | (add rax #x10010203) 103 | ; TODO: use special encoding, as noted in x86-64-syntax.lisp. 104 | ;(add rax 10) 105 | (add rbx 267) 106 | (add r15 #x123456) 107 | (add r10d 3) 108 | (add sil 6) 109 | (add r9l 8) 110 | (add r10 rbx) 111 | (add rsi (rbx)) 112 | (dec di) 113 | (dec ecx) 114 | (dec r10) 115 | (div ebx) 116 | (inc di) 117 | (inc ecx) 118 | (inc r10) 119 | (mul dword (rbx)) 120 | (neg rcx) 121 | (not qword (rbx)) 122 | (sbb rbx rdx) 123 | (test rax 123456789) 124 | (test r12 11223344) 125 | (test qword (rdi) 9966) 126 | (test rdx rdi) 127 | (test (rdx) r9) 128 | 129 | msg (db "Hello World! ") 130 | endmsg) 131 | "Arithmetic instructions are tested separately.") 132 | 133 | (defparameter *arith-code* 134 | '(4 8 5 232 3 128 195 3 128 6 102 126 4 129 195 210 4 129 6 102 126 135 | 46 22 131 193 9 131 6 102 126 12 0 216 0 46 102 126 1 217 1 22 102 136 | 126 2 46 102 126 3 22 102 126 36 8 37 232 3 128 227 3 128 38 102 137 | 126 4 129 227 210 4 129 38 102 126 46 22 131 225 9 131 38 102 126 138 | 12 32 216 32 46 102 126 33 217 33 22 102 126 34 46 102 126 35 22 139 | 102 126 60 8 61 232 3 128 251 3 128 62 102 126 4 129 251 210 4 129 140 | 62 102 126 46 22 131 249 9 131 62 102 126 12 56 216 56 46 102 126 141 | 57 217 57 22 102 126 58 46 102 126 59 22 102 126 75 102 72 254 202 142 | 254 14 102 126 255 74 3 102 255 14 102 126 246 245 246 54 102 126 143 | 247 247 247 114 3 67 102 64 254 194 254 6 102 126 255 66 3 102 255 144 | 6 102 126 246 229 246 38 102 126 247 231 247 98 3 246 221 246 30 145 | 102 126 247 223 247 90 3 246 213 246 22 102 126 247 215 247 82 3 146 | 12 8 13 232 3 128 203 3 128 14 102 126 4 129 203 210 4 129 14 102 147 | 126 46 22 131 201 9 131 14 102 126 12 8 216 8 46 102 126 9 217 9 148 | 22 102 126 10 46 102 126 11 22 102 126 208 230 208 38 102 126 210 149 | 230 210 38 102 126 192 230 5 192 38 102 126 5 209 226 209 38 102 150 | 126 211 226 211 38 102 126 193 226 5 193 38 102 126 5 208 238 208 151 | 46 102 126 210 238 210 46 102 126 192 238 5 192 46 102 126 5 209 152 | 234 209 46 102 126 211 234 211 46 102 126 193 234 5 193 46 102 126 153 | 5 44 8 45 232 3 128 235 3 128 46 102 126 4 129 235 210 4 129 46 154 | 102 126 46 22 131 233 9 131 46 102 126 12 40 216 40 46 102 126 41 155 | 217 41 22 102 126 42 46 102 126 43 22 102 126 168 8 169 232 3 246 156 | 195 3 246 6 102 126 4 247 195 210 4 247 6 102 126 46 22 132 216 157 | 132 46 102 126 133 217 133 22 102 126 52 8 53 232 3 128 243 3 128 158 | 54 102 126 4 129 243 210 4 129 54 102 126 46 22 131 241 9 131 54 159 | 102 126 12 48 216 48 46 102 126 49 217 49 22 102 126 50 46 102 126 160 | 51 22 102 126 102 5 232 3 102 74 77 102 66 69 72 21 69 35 1 0 129 161 | 195 232 3 0 0 72 5 3 2 1 16 72 129 195 11 1 0 0 73 129 199 86 52 162 | 18 0 65 131 194 3 64 128 198 6 65 128 193 8 73 1 218 72 3 51 102 163 | 255 207 255 201 73 255 202 247 243 102 255 199 255 193 73 255 194 164 | 247 35 72 247 217 72 247 19 72 25 211 72 169 21 205 91 7 73 247 165 | 196 48 65 171 0 72 247 7 238 38 0 0 72 133 250 76 133 10 72 101 166 | 108 108 111 32 87 111 114 108 100 33 32)) 167 | 168 | (defparameter *misc-asm* 169 | '((bits 16) 170 | (org #x7c00) 171 | 172 | start 173 | 174 | (align 4) 175 | (bt edx 29) 176 | (align 4) 177 | (btc eax 28) 178 | (btr ebx 27) 179 | (bts ecx 26) 180 | (call msg) 181 | (clc) 182 | (cld) 183 | (cli) 184 | (hlt) 185 | (in al 3) 186 | (in ax 4) 187 | (in al dx) 188 | (in ax dx) 189 | (int 3) 190 | (int #x10) 191 | .loop 192 | (jcxz .loop) 193 | (je .loop) 194 | (jmp short .loop) 195 | (jmp near meta-msg) 196 | (lgdt (msg)) 197 | (lidt (msg)) 198 | (lldt dx) 199 | (lldt (msg)) 200 | (lodsb) 201 | (lodsw) 202 | (lodsd) 203 | (loop .loop) 204 | ;; Segment override prefix. 205 | (es mov bl (di)) 206 | (ds mov byte (si) #xff) 207 | (mov ah 9) 208 | ;; TODO: currently if we use AL in place of BL, generated code is not as efficient as that of NASM; 209 | ;; Will add more instructions e.g. mov al, moffset. 210 | (mov bl (msg)) 211 | (mov (msg) bh) 212 | (mov bx (- endmsg msg)) 213 | (mov ax cx) 214 | (mov (msg) bx) 215 | (mov cx (#x1c7b)) 216 | (mov byte (msg) 42) 217 | (mov word (msg) 123) 218 | (mov es bx) 219 | (mov ax cs) 220 | (mov cr0 eax) 221 | (mov eax cr0) 222 | (movzx ax (msg)) 223 | (movzx edx cx) 224 | (movzx eax byte (msg)) 225 | (movzx eax word (msg)) 226 | (nop) 227 | (out 3 al) 228 | (out 4 ax) 229 | (out dx al) 230 | (out dx ax) 231 | (push cx) 232 | (push edx) 233 | (push cs) 234 | (push ss) 235 | (push ds) 236 | (push es) 237 | (pushf) 238 | (pushfd) 239 | (pop dx) 240 | (pop ecx) 241 | (pop ss) 242 | (pop ds) 243 | (pop es) 244 | (popf) 245 | (popfd) 246 | (rdmsr) 247 | (rep movsb) 248 | (rep movsw) 249 | (rep movsd) 250 | (ret) 251 | (stc) 252 | (std) 253 | (sti) 254 | (stosb) 255 | (stosw) 256 | (stosd) 257 | (wrmsr) 258 | 259 | (bits 64) 260 | (addressing rel) 261 | (bsf ax bx) 262 | (bsf ecx edx) 263 | (bsf r10 (msg)) 264 | (bsr ax r8w) 265 | (bsr r10d r9d) 266 | (bsr rax r12) 267 | (bswap ebx) 268 | (bswap rax) 269 | (bswap r10) 270 | (bt edx 29) 271 | (bt edx ecx) 272 | (bt rdx 30) 273 | (bt rax rbx) 274 | (btc rax 29) 275 | (btr rbx 28) 276 | (bts rcx 27) 277 | (call msg) 278 | (cmova ax bx) 279 | (cmovc eax edx) 280 | (cmove rdx r10) 281 | (cmpxchg cl dl) 282 | (cmpxchg cx dx) 283 | (cmpxchg edi edx) 284 | (cmpxchg rcx r10) 285 | (cmpxchg8b (rbx)) 286 | (cmpxchg16b (rbx)) 287 | (invlpg (abs 0)) 288 | (iretq) 289 | (jb near msg) 290 | (jmp near rbx) 291 | (jmp near msg) 292 | (jmp near (msg)) 293 | (leave) 294 | (lgdt (msg)) 295 | (lidt (msg)) 296 | (lodsq) 297 | (mov eax #x1234) 298 | (mov rsp #x90000) 299 | (mov rax #x1122334455667788) 300 | (mov rcx (msg)) 301 | (mov rcx (abs msg)) 302 | (mov rdi (abs #xb8000)) 303 | (mov rbx rcx) 304 | (mov rax -1) 305 | (mov qword (msg) 1019) 306 | ;; Following two cases test that REX prefix should follow legacy prefixes. 307 | (mov ax r8w) 308 | (fs mov r9w (msg)) ; Not sure whether this case is useful or not. 309 | ;; Following case tests the case that no bit is set for REX prefix. 310 | (mov dil 19) 311 | (movsq) 312 | (movzx r10 al) 313 | (movzx eax byte (msg)) 314 | (movzx rdx word (msg)) 315 | (push r10) 316 | (pushfq) 317 | (pop rax) 318 | (popcnt r11 (msg)) 319 | (popfq) 320 | (sal ebx 1) 321 | (sar edx cl) 322 | (seta ah) 323 | (setz (msg)) 324 | (shl r10 6) 325 | (shr qword (msg) 8) 326 | (rep stosq) 327 | (syscall) 328 | (sysret) 329 | (xadd cl dl) 330 | (xadd cx dx) 331 | (xadd edi edx) 332 | (xadd rcx r10) 333 | (xchg ax bx) 334 | (xchg cx ax) 335 | (xchg eax ebx) 336 | (xchg ecx eax) 337 | (xchg rax rbx) 338 | (xchg rcx rax) 339 | ;; (xchg a b) is equivalent to NASM's xchg b, a. 340 | ;; They are semantically equivalent anyway. 341 | (xchg al cl) 342 | (xchg cx bx) 343 | (xchg edx ebx) 344 | (xchg r10 r15) 345 | 346 | ;; Put these short jump instructions here to avoid the very long jump. 347 | ;; TODO: check near version? 348 | (jecxz msg) 349 | (jrcxz msg) 350 | 351 | (equ hi 4) 352 | meta-msg (dw msg) 353 | (resb 4) 354 | msg (db "Hello World! ") 355 | endmsg 356 | (times 3 db 0) 357 | (dw #xaa55) 358 | (resw 3) 359 | (dd 123456 7891011) 360 | (resd 2) 361 | (dq 3372036854775808) 362 | (resq 1)) 363 | "Miscellaneous instructions.") 364 | 365 | (defparameter *misc-code* 366 | '(102 15 186 226 29 144 144 144 102 15 186 248 28 102 15 186 243 27 102 15 186 367 | 233 26 232 250 1 248 252 250 244 228 3 229 4 236 237 204 205 16 227 254 116 368 | 252 235 250 233 222 1 15 1 22 20 126 15 1 30 20 126 15 0 210 15 0 22 20 126 369 | 172 173 102 173 226 223 38 138 29 62 198 4 255 180 9 138 30 20 126 136 62 20 370 | 126 187 13 0 137 200 137 30 20 126 139 14 123 28 198 6 20 126 42 199 6 20 126 371 | 123 0 142 195 140 200 15 34 192 15 32 192 15 182 6 20 126 102 15 183 209 102 372 | 15 182 6 20 126 102 15 183 6 20 126 144 230 3 231 4 238 239 81 102 82 14 22 30 373 | 6 156 102 156 90 102 89 23 31 7 157 102 157 15 50 243 164 243 165 243 102 165 374 | 195 249 253 251 170 171 102 171 15 48 102 15 188 195 15 188 202 76 15 188 21 375 | 72 1 0 0 102 65 15 189 192 69 15 189 209 73 15 189 196 15 203 72 15 200 73 15 376 | 202 15 186 226 29 15 163 202 72 15 186 226 30 72 15 163 216 72 15 186 248 29 377 | 72 15 186 243 28 72 15 186 233 27 232 15 1 0 0 102 15 71 195 15 66 194 73 15 378 | 68 210 15 176 209 102 15 177 209 15 177 215 76 15 177 209 15 199 11 72 15 199 379 | 11 15 1 60 37 0 0 0 0 72 207 15 130 223 0 0 0 255 227 233 216 0 0 0 255 37 210 380 | 0 0 0 201 15 1 21 202 0 0 0 15 1 29 195 0 0 0 72 173 184 52 18 0 0 188 0 0 9 0 381 | 72 184 136 119 102 85 68 51 34 17 72 139 13 166 0 0 0 72 139 12 37 20 126 0 0 382 | 72 139 60 37 0 128 11 0 72 137 203 72 199 192 255 255 255 255 72 199 5 129 0 0 383 | 0 251 3 0 0 102 68 137 192 100 102 68 139 13 116 0 0 0 64 183 19 72 165 76 15 384 | 182 208 15 182 5 100 0 0 0 72 15 183 21 92 0 0 0 65 82 156 88 243 76 15 184 29 385 | 79 0 0 0 157 209 227 211 250 15 151 196 15 148 5 64 0 0 0 73 193 226 6 72 193 386 | 45 52 0 0 0 8 243 72 171 15 5 15 7 15 192 209 102 15 193 209 15 193 215 76 15 387 | 193 209 102 147 102 145 147 145 72 147 72 145 134 200 102 135 217 135 218 77 388 | 135 250 103 227 8 227 6 20 126 0 0 0 0 72 101 108 108 111 32 87 111 114 108 389 | 100 33 32 0 0 0 85 170 0 0 0 0 0 0 64 226 1 0 67 104 120 0 0 0 0 0 0 0 0 0 0 0 390 | 230 130 217 250 11 0 0 0 0 0 0 0 0 0)) 391 | 392 | (defparameter *address-asm* 393 | '((org #x7c00) 394 | 395 | (bits 16) 396 | (mov (bp) es) 397 | (mov (bx si) ds) 398 | (mov (bx di) es) 399 | (mov (bp si) ds) 400 | (mov (bp di) ss) 401 | (mov (si) ds) 402 | (mov (di) cs) 403 | (mov (32330) ds) 404 | (mov (msg) ds) 405 | (mov (bx) cs) 406 | (mov (bx si 1) ds) 407 | (mov (bx di 2) es) 408 | (mov (bp si 3) ds) 409 | (mov (bp di 4) ss) 410 | (mov (si 5) ds) 411 | (mov (di 6) cs) 412 | (mov (bp 7) ds) 413 | (mov (bx 8) cs) 414 | (mov ds (di)) 415 | (mov ds (bx si 1001)) 416 | (mov es (bx di 1002)) 417 | (mov ds (bp si 1003)) 418 | (mov ss (bp di 1004)) 419 | (mov ds (si 1005)) 420 | (mov es (di 1006)) 421 | (mov ds (bp 1007)) 422 | (mov es (bx 1008)) 423 | 424 | (bits 32) 425 | (mov (ebp) ebx) 426 | (mov (esp) ecx) 427 | (mov (123456) edx) 428 | (mov (eax) edx) 429 | (mov (ebp 36) ecx) 430 | (mov (edi 1234) edx) 431 | (mov (esi 123456) ecx) 432 | (mov (esp #x23) ebx) 433 | (mov (esp #x12345678) ecx) 434 | (mov (eax ebx) ecx) 435 | (mov (esi edi) edx) 436 | (mov (esi ebp) edx) 437 | ;; (mov (eax*2 3456) edx) ; NASM encodes as (eax eax 3456) 438 | (mov (eax*2 esi) edx) 439 | (mov (esi*2 ebp 123) edx) 440 | (mov (edi*2 ebx 8) ecx) 441 | (mov (ecx*4 ebp 123) edx) 442 | (mov (esi*4 edx 8) ecx) 443 | (mov (edx*8 ebp 123456) ebx) 444 | (mov (edi*8 ecx 8) edx) 445 | 446 | (bits 64) 447 | (mov (rbp) rbx) 448 | (mov (rsp) rcx) 449 | (mov (abs 123456) rdx) 450 | (mov (rax) rdx) 451 | (mov (rbp 36) rcx) 452 | (mov (rdi 1234) rdx) 453 | (mov (rsi 123456) rcx) 454 | (mov (rsp #x23) rbx) 455 | (mov (rsp #x12345678) rcx) 456 | (mov (rax rbx) rcx) 457 | (mov (rsi rdi) rdx) 458 | (mov (rsi rbp) rdx) 459 | ;; (mov (rax*2 3456) rdx) ; NASM encodes as (rax rax 3456) 460 | (mov (rax*2 rsi) rdx) 461 | (mov (rsi*2 rbp 123) rdx) 462 | (mov (rdi*2 rbx 8) rcx) 463 | (mov (rcx*4 rbp 123) rdx) 464 | (mov (rsi*4 rdx 8) rcx) 465 | (mov (rdx*8 rbp 123456) rbx) 466 | (mov (rdi*8 rcx 8) rdx) 467 | 468 | msg (db "Hello World! ") 469 | endmsg) 470 | "Test addressing modes.") 471 | 472 | (defparameter *address-code* 473 | '(140 70 0 140 24 140 1 140 26 140 19 140 28 140 13 140 30 74 126 474 | 140 30 5 125 140 15 140 88 1 140 65 2 140 90 3 140 83 4 140 92 5 475 | 140 77 6 140 94 7 140 79 8 142 29 142 152 233 3 142 129 234 3 142 476 | 154 235 3 142 147 236 3 142 156 237 3 142 133 238 3 142 158 239 3 477 | 142 135 240 3 137 93 0 137 12 36 137 21 64 226 1 0 137 16 137 77 478 | 36 137 151 210 4 0 0 137 142 64 226 1 0 137 92 36 35 137 140 36 479 | 120 86 52 18 137 12 24 137 20 62 137 20 46 137 20 70 137 84 117 480 | 123 137 76 123 8 137 84 141 123 137 76 178 8 137 156 213 64 226 1 481 | 0 137 84 249 8 72 137 93 0 72 137 12 36 72 137 20 37 64 226 1 0 72 482 | 137 16 72 137 77 36 72 137 151 210 4 0 0 72 137 142 64 226 1 0 72 483 | 137 92 36 35 72 137 140 36 120 86 52 18 72 137 12 24 72 137 20 62 484 | 72 137 20 46 72 137 20 70 72 137 84 117 123 72 137 76 123 8 72 137 485 | 84 141 123 72 137 76 178 8 72 137 156 213 64 226 1 0 72 137 84 249 486 | 8 72 101 108 108 111 32 87 111 114 108 100 33 32)) 487 | 488 | (defparameter *bootloader-code* 489 | '(180 3 205 16 184 1 19 187 15 0 185 15 0 189 20 124 205 16 235 254 490 | 72 101 108 108 111 32 87 111 114 108 100 33 32 13 10 0 0 0 0 0 0 0 491 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 492 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 493 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 494 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 495 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 496 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 497 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 498 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 499 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 501 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 502 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 503 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 504 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 505 | 0 0 0 0 0 0 85 170)) 506 | 507 | (deftest test-cc () 508 | (check 509 | (equal (asm *address-asm*) *address-code*) 510 | (equal (asm *arith-asm*) *arith-code*) 511 | (equal (asm *misc-asm*) *misc-code*))) 512 | -------------------------------------------------------------------------------- /cc/test.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Test suite. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2015 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (deftest test () 14 | (combine-results 15 | (test-cc) 16 | (test-abi))) 17 | -------------------------------------------------------------------------------- /cc/unit-test.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Unit test, adapted from chapter 9 of Practical Common Lisp. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2009-2012 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defmacro with-gensyms ((&rest names) &body body) 14 | "Environment for a list of gensyms." 15 | `(let ,(loop for n in names collect `(,n (gensym))) 16 | ,@body)) 17 | 18 | (defvar *test-name* nil) 19 | (defmacro deftest (name parameters &body body) 20 | "Define a test function. Within a test function we can call 21 | other test functions or use 'check' to run individual test 22 | cases." 23 | `(defun ,name ,parameters 24 | (let ((*test-name* (list ',name))) 25 | ,@body))) 26 | 27 | (defmacro check (&body forms) 28 | "Run each expression in 'forms' as a test case." 29 | `(combine-results 30 | ,@(loop for f in forms collect `(report-result ,f ',f)))) 31 | 32 | (defmacro combine-results (&body forms) 33 | "Combine the results (as booleans) of evaluating 'forms' in order." 34 | (with-gensyms (result) 35 | `(let ((,result t)) 36 | ,@(loop for f in forms collect `(unless ,f (setf ,result nil))) 37 | ,result))) 38 | 39 | (defun report-result (result form) 40 | "Report the results of a single test case. Called by 'check'." 41 | (format t "~:[FAIL~;pass~] ~a: ~a~%" result (car *test-name*) form) 42 | result) 43 | 44 | -------------------------------------------------------------------------------- /cc/util.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Utilities. 6 | ;;;; License: 7 | ;;;; GNU General Public License v2 8 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 9 | ;;;; Copyright (C) 2009-2012 Yujian Zhang 10 | 11 | (in-package :cc) 12 | 13 | (defmacro aif (test-form then-form &optional else-form) 14 | "Anaphoric variant of if. From ON LISP." 15 | `(let ((it ,test-form)) 16 | (if it ,then-form ,else-form))) 17 | 18 | (defmacro acond (&rest clauses) 19 | "Anaphoric variant of cond. From ON LISP." 20 | (if (null clauses) 21 | nil 22 | (let ((cl1 (car clauses)) 23 | (sym (gensym))) 24 | `(let ((,sym ,(car cl1))) 25 | (if ,sym 26 | (let ((it ,sym)) ,@(cdr cl1)) 27 | (acond ,@(cdr clauses))))))) 28 | 29 | (defun str (&rest args) 30 | "Take any number of arguments and concatenates their printed 31 | representations into a string. From ON LISP." 32 | (with-output-to-string (s) 33 | (dolist (a args) (princ a s)))) 34 | 35 | (defun symb (&rest args) 36 | "Takes one or more arguments and returns the symbol whose printname 37 | is their concatenation. From ON LISP." 38 | (values (intern (apply #'str args)))) 39 | 40 | (defun mklist (obj) 41 | "Returns obj if it is already a list; otherwise lispy it. From ON LISP." 42 | (if (listp obj) 43 | obj 44 | (list obj))) 45 | 46 | (defun repeat-element (n element) 47 | (loop for i from 0 below n collect element)) 48 | 49 | (defun repeat-list (n list) 50 | (case n 51 | (0 nil) 52 | (1 list) 53 | (t (if (< n 0) 54 | (error "repeat-list: invalid n=~A" n) 55 | (append list (repeat-list (1- n) list)))))) 56 | 57 | (defun assoc* (&rest args) 58 | "Return the cdr of the result of assoc." 59 | (cdr (apply #'assoc args))) 60 | 61 | (defun segment (list n) 62 | "Segment list with each sublist containing n elements." 63 | (cond 64 | ((null list) nil) 65 | ((<= (length list) n) (list list)) 66 | (t (append (list (subseq list 0 n)) (segment (nthcdr n list) n))))) 67 | 68 | (defun printable? (c) 69 | "Returns T if char (as integer) is printable." 70 | (<= 32 c 126)) ; Seems that graphic-char-p allows more chars as printable. 71 | 72 | (defun pp-char (c) 73 | "Returns the character form of c if printable; otherwise ." 74 | (if (printable? c) (code-char c) #\.)) 75 | 76 | (defun pp-hex (s) 77 | "Pretty print S (stream of bytes) in hexadecimal manner. Output is 78 | same as Emacs hexl-mode." 79 | (format 80 | t "87654321 0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789abcdef~%") 81 | (let ((ss (segment s 16))) 82 | (loop for i from 0 below (length ss) 83 | do (format t "~8,'0X: ~{~{~2,'0X~} ~}~51T~{~c~}~%" 84 | (* i 16) (segment (nth i ss) 2) 85 | (mapcar #'pp-char (nth i ss)))))) 86 | -------------------------------------------------------------------------------- /cc/vga-text.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; VGA text mode functions. 6 | ;;;; BIOS interruptions are not used. 7 | ;;;; License: 8 | ;;;; GNU General Public License v2 9 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 10 | ;;;; Copyright (C) 2009-2015 Yujian Zhang 11 | 12 | (in-package :cc) 13 | 14 | (defparameter *vga-text-constants* 15 | `( 16 | ;;; VGA text mode related constants. 17 | 18 | ;;; ASCII characters. 19 | (equ ascii-backspace #x08) 20 | (equ ascii-linefeed #x0a) 21 | (equ ascii-space #x20) 22 | )) 23 | 24 | (defparameter *vga-text-16* 25 | ;;; VGA text output code in 16 bit mode, based on http://wiki.osdev.org/Babystep4 26 | ;;; We only implement minimal set of features in 16 bit mode as the main intention 27 | ;;; is only to print error messages. 28 | `( 29 | ;;; Initialize text mode. Call it before calling any text mode functions. 30 | init-text-mode-16 31 | (xor ax ax) 32 | (mov ds ax) 33 | (mov ax #xb800) ; Text video memory 34 | (mov es ax) 35 | (call clear-16) 36 | (ret) 37 | 38 | ;;; Clear screen. 39 | clear-16 40 | (movzx ax (text-rows-16)) 41 | (movzx dx (text-cols-16)) 42 | (mul dx) 43 | (movzx ecx ax) ; All screen to be cleared. 44 | (mov ax #x0f20) ; Black background, white foreground, space char. 45 | (mov di 0) 46 | (rep stosw) 47 | (ret) 48 | 49 | ;;; Function println-16. Write a string and start a new line. 50 | ;;; It is equivalent to calling print twice: first to print the string, 51 | ;;; and then print CR/LF. 52 | ;;; Input: 53 | ;;; DS:SI: points to the starting address of the 0 terminated string. 54 | ;;; Output: None 55 | ;;; Modified registers: same as putchar 56 | ;;; Global variables: same as putchar 57 | println-16 58 | (call print-16) 59 | (call printlf-16) 60 | (ret) 61 | 62 | ;;; Function printlf-16. Print crlf only. 63 | ;;; Input: None 64 | ;;; Output: None 65 | ;;; Modified reisters: None 66 | ;;; Global variables: text-x-16, text-y-16 67 | printlf-16 68 | (add byte (text-y-16) 1) ; Down one row 69 | (mov byte (text-x-16) 0) ; Back to left 70 | (ret) 71 | 72 | do-char-16 73 | (call putchar-16) 74 | ;;; Function print-16. Write string to screen. 75 | ;;; Input: 76 | ;;; DS:SI: points to the starting address of the 0 terminated string. 77 | ;;; Output: None 78 | ;;; Modified registers: same as putchar 79 | ;;; Global variables: same as putchar 80 | print-16 81 | (lodsb) ; Load string char to AL 82 | (cmp al 0) ; 0 terminated string like C. 83 | (jne do-char-16) 84 | (ret) 85 | 86 | ;;; Function putchar-16. Writer character at cursor position. 87 | ;;; Input: 88 | ;;; AL: character to display 89 | ;;; Output: None 90 | ;;; Modified registers: AX, BX, CX, DX, DI 91 | ;;; Global variables: text-x-16, text-y-16, text-cols-16 92 | putchar-16 93 | (mov ah #xf) ; Attribute: white on black 94 | (mov cx ax) ; Save char/attribute 95 | (movzx ax (text-y-16)) 96 | (movzx dx (text-cols-16)) 97 | (shl dx 1) ; 2 bytes for one character 98 | (mul dx) 99 | (movzx bx (text-x-16)) 100 | (shl bx 1) 101 | (mov di 0) ; Start of video memory 102 | (add di ax) ; Add y offset 103 | (add di bx) ; Add x offset 104 | (mov ax cx) ; Restore char/attribute 105 | (stosw) ; Write char/atribute 106 | (add byte (text-x-16) 1) ; Advance to right 107 | (ret) 108 | 109 | text-rows-16 (db 25) ;; Number of rows in text mode. 110 | text-cols-16 (db 80) ;; Number of columns in text mode. 111 | text-x-16 (db 0) ;; Position x in text mode [0, text-cols-16) 112 | text-y-16 (db 0) ;; Position y in text mode [0, text-rows-16) 113 | )) 114 | 115 | (defparameter *vga-text* 116 | ;;; VGA text output in 64 bit mode. 117 | `( 118 | (equ vga-video-memory (+ kernel-virtual-base #xb8000)) 119 | ;; Blue background, white foreground, space char. 120 | (equ background-filling #x1f201f20) 121 | 122 | ;;; Clear screen. 123 | ,@(def-fun 'clear nil 124 | `( 125 | (movzx eax byte (text-rows)) 126 | (movzx edx byte (text-cols)) 127 | (mul edx) 128 | (shr eax 1) 129 | (mov ecx eax) ; All screen to be cleared. 130 | (mov eax background-filling) 131 | (mov rdi vga-video-memory) 132 | (rep stosd) 133 | (mov byte (text-x) 0) 134 | (mov byte (text-y) 0) 135 | ,@(call-function 'set-cursor))) 136 | 137 | ;;; Function println. Write a string and start a new line. 138 | ;;; It is equivalent to calling print twice: first to print the string, 139 | ;;; and then print CR/LF. 140 | ;;; Input: 141 | ;;; RSI: points to the starting address of the 0 terminated string. 142 | ;;; Output: None 143 | ;;; Modified registers: same as putchar 144 | ;;; Global variables: same as putchar 145 | ,@(def-fun 'println nil 146 | `( 147 | ,@(call-function 'print) 148 | ,@(call-function 'printlf))) 149 | 150 | ;;; Function printlf. Print crlf only. 151 | ;;; Input: None 152 | ;;; Output: None 153 | ;;; Modified registers: EAX 154 | ;;; Global variables: text-x, text-y 155 | ,@(def-fun 'printlf nil 156 | `( 157 | (inc byte (text-y)) ; Down one row 158 | (mov byte (text-x) 0) ; Back to left 159 | (mov al (text-y)) 160 | (cmp al (text-rows)) 161 | (jb .done) 162 | ,@(call-function 'scroll-up) 163 | .done 164 | ,@(call-function 'set-cursor))) 165 | 166 | ;;; Function print. Write string to screen. 167 | ;;; Input: 168 | ;;; RDI: points to the starting address of the 0 terminated string. 169 | ;;; Output: None 170 | ;;; Modified registers: same as putchar 171 | ;;; Global variables: same as putchar 172 | ,@(def-fun 'print nil 173 | `( 174 | (mov rsi rdi) 175 | .start 176 | (lodsb) ; Load string char to AL 177 | (cmp al 0) ; 0 terminated string like C. 178 | (je .done) 179 | (mov dil al) 180 | ,@(call-function 'putchar) 181 | (jmp short .start) 182 | .done 183 | )) 184 | 185 | ;;; Function putchar. Writer character at cursor position. 186 | ;;; Input: 187 | ;;; DIL: character to display 188 | ;;; Output: None 189 | ;;; Modified registers: RAX, RCX, RDX, RDI, R8, R9 190 | ;;; Global variables: text-x, text-y, text-cols 191 | ,@(def-fun 'putchar nil 192 | `( 193 | (cmp dil ascii-linefeed) 194 | (je .next-line) 195 | (mov r8d #x1f00) ; Attribute: white on blue 196 | (mov r8l dil) ; Save char/attribute 197 | (movzx eax byte (text-y)) 198 | (movzx edx byte (text-cols)) 199 | (shl edx 1) ; 2 bytes for one character 200 | (mul edx) 201 | (movzx r9d byte (text-x)) 202 | (shl r9d 1) 203 | (mov rdi vga-video-memory) ; Start of video memory 204 | (add rdi rax) ; Add y offset 205 | (add rdi r9) ; Add x offset 206 | (mov ax r8w) ; Restore char/attribute 207 | (stosw) ; Write char/atribute 208 | (inc byte (text-x) 1) ; Advance to right 209 | (mov al (text-x)) 210 | (cmp al (text-cols)) 211 | (je .next-line) 212 | (jmp short .done) 213 | .next-line 214 | ,@(call-function 'printlf) 215 | .done 216 | ,@(call-function 'set-cursor))) 217 | 218 | ;;; Function scroll-up. Scroll the screen up one line. 219 | ;;; Input: None 220 | ;;; Output: None 221 | ;;; Modified registers: RAX, RCX, RDX, RDI, RSI 222 | ;;; Global variables: text-x, text-y, text-rows, text-cols 223 | ,@(def-fun 'scroll-up '(rbx) 224 | '( 225 | ;; Copy rows from (1 to text-rows - 1) to (0 to text-fows - 2) 226 | (movzx ebx byte (text-cols)) 227 | (movzx eax byte (text-rows)) 228 | (dec eax) ; Only copy text-rows - 1 lines. 229 | (mul ebx) 230 | (shr eax 1) ; 2 bytes per character, write 4 bytes with movsd 231 | (shl ebx 1) ; Number of bytes per line. 232 | (mov rdi vga-video-memory) 233 | (mov rsi rdi) 234 | (add rsi rbx) 235 | (mov ecx eax) 236 | (cld) 237 | ;; TODO: change to movsq 238 | (rep movsd) 239 | ;; Clear the last line. 240 | (mov eax background-filling) 241 | (shr ebx 2) ; As we're using stosd, divide by 4. 242 | (mov ecx ebx) 243 | (rep stosd) 244 | ;; Reset the y position to the last line. 245 | (dec byte (text-y)))) 246 | 247 | ;;; Function backspace-char. Remove one character before cursor, 248 | ;;; and move cursor one character back. 249 | ,@(def-fun 'backspace-char nil 250 | `( 251 | ;; If the cursor just follows prompt (e.g. REPL> ), then backspace 252 | ;; does nothing. 253 | (cmp byte (text-x) prompt-length) 254 | (jbe .done) 255 | ;; First go back one character and write a space. 256 | (dec byte (text-x)) 257 | (mov dil ascii-space) 258 | ,@(call-function 'putchar) 259 | ;; Go back once more and set cursor. 260 | (dec byte (text-x)) 261 | ,@(call-function 'set-cursor) 262 | .done 263 | )) 264 | 265 | ;;; Function set-cursor. Set VGA hardware cursor. 266 | ;;; Input: based on text-xy, text-y 267 | ;;; Output: None 268 | ;;; Modified registers: RAX, RCX, RDX, RDI 269 | ;;; Global variables: text-x, text-y, text-cols 270 | ;;; Based on http://www.brokenthorn.com/Resources/OSDev10.html 271 | (equ crt-index-reg #x3d4) 272 | (equ crt-data-reg #x3d5) 273 | (equ cursor-location-high #xe) 274 | (equ cursor-location-low #xf) 275 | ,@(def-fun 'set-cursor nil 276 | `( 277 | ;; Get current cursor position. Note that we only care about the 278 | ;; location, not the memory (as in putchar). So following equation 279 | ;; is used: location = text-x + text-y * text-cols 280 | (movzx eax byte (text-y)) 281 | (movzx edx byte (text-cols)) 282 | (mul edx) 283 | (movzx ecx byte (text-x)) 284 | (add ecx eax) 285 | ;; Set low byte index to vga register. 286 | (mov al cursor-location-low) 287 | (mov dx crt-index-reg) 288 | (out dx al) 289 | (mov al cl) 290 | (mov dx crt-data-reg) 291 | (out dx al) 292 | ;; Set high byte index to vga register. 293 | (mov al cursor-location-high) 294 | (mov dx crt-index-reg) 295 | (out dx al) 296 | (mov al ch) 297 | (mov dx crt-data-reg) 298 | (out dx al))) 299 | 300 | text-rows (db 25) ;; Number of rows in text mode. 301 | text-cols (db 80) ;; Number of columns in text mode. 302 | text-x (db 0) ;; Position x in text mode [0, text-cols) 303 | text-y (db 0) ;; Position y in text mode [0, text-rows) 304 | )) 305 | -------------------------------------------------------------------------------- /cc/x86-64-syntax.lisp: -------------------------------------------------------------------------------- 1 | ;;;; -*- Mode: Lisp -*- 2 | ;;;; Author: 3 | ;;;; Yujian Zhang 4 | ;;;; Description: 5 | ;;;; Syntax tables for x86-64. 6 | ;;;; References: 7 | ;;;; [1] Intel 64 and IA-32 Architectures Software Developer's Manual 8 | ;;;; Volume 2, Instruction Set Reference, A-Z. June 2015 9 | ;;;; License: 10 | ;;;; GNU General Public License v2 11 | ;;;; http://www.gnu.org/licenses/gpl-2.0.html 12 | ;;;; Copyright (C) 2009-2015 Yujian Zhang 13 | 14 | (in-package :cc) 15 | 16 | (defun arith-syntax-1 (mnemonic 64bit-only?) 17 | "Return syntax table for arithmetic operations: 18 | adc/add/and/cmp/or/sbb/sub/xor." 19 | (let ((base ; Base opcode for operation on r/m8 r8. 20 | (ecase mnemonic 21 | (adc #x10) (add #x00) (and #x20) (cmp #x38) 22 | (or #x08) (sbb #x18) (sub #x28) (xor #x30))) 23 | (opcode ; Opcode used when one operand is immediate. 24 | (ecase mnemonic 25 | (adc '/2) (add '/0) (and '/4) (cmp '/7) 26 | (or '/1) (sbb '/3) (sub '/5) (xor '/6)))) 27 | (if 64bit-only? 28 | `(;; TODO: For imm8, encode with imm8 with generic r64 29 | ;; (instead of rax) seems to save 3 bytes. 30 | ((,mnemonic rax imm32) . (rex.w ,(+ base #x05) id)) 31 | ((,mnemonic (r/m64 r64) (imm32 imm16)) . (rex.w #x81 ,opcode id)) 32 | ((,mnemonic qword m (imm32 imm16)) . (rex.w #x81 ,opcode id)) 33 | ((,mnemonic (r/m64 r64) imm8) . (rex.w #x83 ,opcode ib)) 34 | ((,mnemonic qword m imm8) . (rex.w #x83 ,opcode ib)) 35 | ((,mnemonic (r/m64 r64 m) r64) . (rex.w ,(+ base #x01) /r)) 36 | ((,mnemonic r64 (r/m64 r64 m)) . (rex.w ,(+ base #x03) /r))) 37 | `(((,mnemonic al imm8) . (,(+ base #x04) ib)) 38 | ((,mnemonic ax imm16) . (o16 ,(+ base #x05) iw)) 39 | ((,mnemonic eax imm32) . (o32 ,(+ base #x05) id)) 40 | ((,mnemonic (r/m8 r8) imm8) . (#x80 ,opcode ib)) 41 | ((,mnemonic byte m imm8) . (#x80 ,opcode ib)) 42 | ((,mnemonic (r/m16 r16) imm8) . (o16 #x83 ,opcode ib)) 43 | ((,mnemonic (r/m32 r32) imm8) . (o32 #x83 ,opcode ib)) 44 | ((,mnemonic word m imm8) . (o16 #x83 ,opcode ib)) 45 | ((,mnemonic dword m imm8) . (o32 #x83 ,opcode ib)) 46 | ((,mnemonic (r/m16 r16) imm16) . (o16 #x81 ,opcode iw)) 47 | ((,mnemonic word m imm16) . (o16 #x81 ,opcode iw)) 48 | ((,mnemonic (r/m32 r32) (imm32 imm16)) . (o32 #x81 ,opcode id)) 49 | ((,mnemonic dword m (imm32 imm16)) . (o32 #x81 ,opcode id)) 50 | ((,mnemonic r/m8 r8) . (,base /r)) 51 | ((,mnemonic (r/m16 r16 m) r16) . (o16 ,(+ base #x01) /r)) 52 | ((,mnemonic (r/m32 r32 m) r32) . (o32 ,(+ base #x01) /r)) 53 | ((,mnemonic r8 r/m8) . (,(+ base #x02) /r)) 54 | ((,mnemonic r16 (r/m16 r16 m)) . (o16 ,(+ base #x03) /r)) 55 | ((,mnemonic r32 (r/m32 r32 m)) . (o32 ,(+ base #x03) /r)))))) 56 | 57 | (defun arith-syntax-2 (mnemonic 64bit-only?) 58 | "Return syntax table for arithmetic operations: div/mul/neg/not." 59 | (let ((opcode (ecase mnemonic 60 | (div '/6) (mul '/4) (neg '/3) (not '/2)))) 61 | (if 64bit-only? 62 | `(((,mnemonic (r/m64 r64)) . (rex.w #xf7 ,opcode)) 63 | ((,mnemonic qword m) . (rex.w #xf7 ,opcode))) 64 | `(((,mnemonic (r/m8 r8)) . (#xf6 ,opcode)) 65 | ((,mnemonic byte m) . (#xf6 ,opcode)) 66 | ((,mnemonic (r/m16 r16)) . (o16 #xf7 ,opcode)) 67 | ((,mnemonic word m) . (o16 #xf7 ,opcode)) 68 | ((,mnemonic (r/m32 r32)) . (o32 #xf7 ,opcode)) 69 | ((,mnemonic dword m) . (o32 #xf7 ,opcode)))))) 70 | 71 | (defun shift-syntax (mnemonic 64bit-only?) 72 | "Return syntax table for shift operations: sal/sar/shl/shr." 73 | (let ((opcode (ecase mnemonic 74 | (sal '/4) (sar '/7) (shl '/4) (shr '/5)))) 75 | (if 64bit-only? 76 | `(((,mnemonic r64 1) . (rex.w #xd1 ,opcode)) 77 | ((,mnemonic qword m 1) . (rex.w #xd1 ,opcode)) 78 | ((,mnemonic r64 cl) . (rex.w #xd3 ,opcode)) 79 | ((,mnemonic qword m cl) . (rex.w #xd3 ,opcode)) 80 | ((,mnemonic r64 imm8) . (rex.w #xc1 ,opcode ib)) 81 | ((,mnemonic qword m imm8) . (rex.w #xc1 ,opcode ib))) 82 | `(((,mnemonic r8 1) . (#xd0 ,opcode)) 83 | ((,mnemonic byte m 1) . (#xd0 ,opcode)) 84 | ((,mnemonic r8 cl) . (#xd2 ,opcode)) 85 | ((,mnemonic byte m cl) . (#xd2 ,opcode)) 86 | ((,mnemonic r8 imm8) . (#xc0 ,opcode ib)) 87 | ((,mnemonic byte m imm8) . (#xc0 ,opcode ib)) 88 | ((,mnemonic r16 1) . (o16 #xd1 ,opcode)) 89 | ((,mnemonic word m 1) . (o16 #xd1 ,opcode)) 90 | ((,mnemonic r16 cl) . (o16 #xd3 ,opcode)) 91 | ((,mnemonic word m cl) . (o16 #xd3 ,opcode)) 92 | ((,mnemonic r16 imm8) . (o16 #xc1 ,opcode ib)) 93 | ((,mnemonic word m imm8) . (o16 #xc1 ,opcode ib)) 94 | ((,mnemonic r32 1) . (o32 #xd1 ,opcode)) 95 | ((,mnemonic dword m 1) . (o32 #xd1 ,opcode)) 96 | ((,mnemonic r32 cl) . (o32 #xd3 ,opcode)) 97 | ((,mnemonic dword m cl) . (o32 #xd3 ,opcode)) 98 | ((,mnemonic r32 imm8) . (o32 #xc1 ,opcode ib)) 99 | ((,mnemonic dword m imm8) . (o32 #xc1 ,opcode ib)))))) 100 | 101 | (defun bit-syntax (mnemonic 64bit-only?) 102 | "Return syntax table for arithmetic operations: bt/btc/btr/bts." 103 | (let ((base ; Base opcode for operation on r/m16, r16, r/m32, r32, r/m64, r64. 104 | (ecase mnemonic 105 | (bt #x0) (btc #x18) (btr #x10) (bts #x8))) 106 | (opcode ; Opcode used when one operand is immediate. 107 | (ecase mnemonic 108 | (bt '/4) (btc '/7) (btr '/6) (bts '/5)))) 109 | (if 64bit-only? 110 | `(((,mnemonic r/m64 r64) . (rex.w #x0f ,(+ base #xa3) /r)) 111 | ((,mnemonic r/m64 imm8) . (rex.w #x0f #xba ,opcode ib))) 112 | `(((,mnemonic r/m16 r16) . (o16 #x0f ,(+ base #xa3) /r)) 113 | ((,mnemonic r/m32 r32) . (o32 #x0f ,(+ base #xa3) /r)) 114 | ((,mnemonic r/m16 imm8) . (o16 #x0f #xba ,opcode ib)) 115 | ((,mnemonic r/m32 imm8) . (o32 #x0f #xba ,opcode ib)))))) 116 | 117 | ;;; Following are syntax tables for x86-64. For each entry, 1st part 118 | ;;; is the instruction type, 2nd part is the corresponding opcode. 119 | ;;; Note that for the 1st part, list may be used for the operand to 120 | ;;; match the type (e.g. imm8 converted to imm16). Note that the 121 | ;;; canonical form should be placed first (e.g. if the operand type 122 | ;;; should be imm16, place it as the car of the list). 123 | ;;; 124 | ;;; For details, 125 | ;;; refer to https://github.com/whily/yalo/blob/master/doc/AssemblyX64.md 126 | 127 | (defparameter *x86-64-syntax-common* 128 | `( 129 | ,@(arith-syntax-1 'adc nil) 130 | ,@(arith-syntax-1 'add nil) 131 | ,@(arith-syntax-1 'and nil) 132 | ((bswap r32) . (#x0f (+ #xc8 r))) 133 | ,@(bit-syntax 'bt nil) 134 | ,@(bit-syntax 'btc nil) 135 | ,@(bit-syntax 'btr nil) 136 | ,@(bit-syntax 'bts nil) 137 | ((bsf r16 r/m16) . (o16 #x0f #xbc /r)) 138 | ((bsf r32 r/m32) . (o32 #x0f #xbc /r)) 139 | ((bsr r16 r/m16) . (o16 #x0f #xbd /r)) 140 | ((bsr r32 r/m32) . (o32 #x0f #xbd /r)) 141 | ((call (imm32 imm64 imm16 imm8 label)) . (o32 #xe8 cd)) 142 | ;; Below is just an hack so that we can always use 32 bit operand 143 | ;; when operating in 32 bit mode. TODO. 144 | ;; As current assembler did not differentiate too much between 16 145 | ;; bit and 32 bit mode, as we need 32 bit operand size for near 146 | ;; relative call in 32 bit, one SHOULD always use call32 below to 147 | ;; call function when working in 32 bit mode (so far in our 148 | ;; bootloader, 32 bit mode is transient as we just setup paging 149 | ;; and goes to 64 bit mode. 150 | ;; Warning: simply using `call` might result in stack corruption 151 | ;; (as 16 bit IP is pushed to stack instead of 32 bit), and memory exception 152 | ;; might occur when return using wrong EIP. 153 | ((call32 (imm32 imm64 imm16 imm8 label)) . (o32 #xe8 cd)) 154 | ((clc) . (#xf8)) 155 | ((cld) . (#xfc)) 156 | ((cli) . (#xfa)) 157 | ((cmovcc r16 r/m16) . (o16 #x0f (+ #x40 cc) /r)) 158 | ((cmovcc r32 r/m32) . (o32 #x0f (+ #x40 cc) /r)) 159 | ,@(arith-syntax-1 'cmp nil) 160 | ((cmpxchg r/m8 r8) . (#x0f #xb0 /r)) 161 | ((cmpxchg r/m16 r16) . (o16 #x0f #xb1 /r)) 162 | ((cmpxchg r/m32 r32) . (o32 #x0f #xb1 /r)) 163 | ((cmpxchg8b m) . (#x0f #xc7 /1)) 164 | ((cpuid) . (#x0f #xa2)) 165 | ((dec (r/m8 r8)) . (#xfe /1)) 166 | ((dec byte m) . (#xfe /1)) 167 | ((dec (r/m16 r16)) . (o16 #xff /1)) 168 | ((dec word m) . (o16 #xff /1)) 169 | ((dec (r/m32 r32)) . (o32 #xff /1)) 170 | ((dec dword m) . (o32 #xff /1)) 171 | ,@(arith-syntax-2 'div nil) 172 | ((hlt) . (#xf4)) 173 | ((in al imm8) . (#xe4 ib)) 174 | ((in ax imm8) . (#xe5 ib)) 175 | ((in al dx) . (#xec)) 176 | ((in ax dx) . (#xed)) 177 | ((inc (r/m8 r8)) . (#xfe /0)) 178 | ((inc byte m) . (#xfe /0)) 179 | ((inc (r/m16 r16)) . (o16 #xff /0)) 180 | ((inc word m) . (o16 #xff /0)) 181 | ((inc (r/m32 r32)) . (o32 #xff /0)) 182 | ((inc dword m) . (o32 #xff /0)) 183 | ((int 3) . (#xcc)) 184 | ((int imm8) . (#xcd ib)) 185 | ((invlpg m) . (#x0f #x01 /7)) 186 | ((jcc (imm8 label imm16 imm32 imm64)) . ((+ #x70 cc) cb)) 187 | ((jcc near (imm32 label imm8 imm16 imm64)) . (#x0f (+ #x80 cc) cd)) 188 | ((jecxz (imm8 label imm16 imm32 imm64)) . (a32 #xe3 cb)) 189 | ((jmp short (imm8 label imm16 imm32 imm64)) . (#xeb cb)) 190 | ((lgdt m) . (#x0f #x01 /2)) 191 | ((lidt m) . (#x0f #x01 /3)) 192 | ((lldt r/m16) . (#x0f #x00 /2)) 193 | ((lodsb) . (#xac)) 194 | ((lodsw) . (o16 #xad)) 195 | ((lodsd) . (o32 #xad)) 196 | ((loop (imm8 label imm16 imm32 imm64)) . (#xe2 cb)) 197 | ((mov r8 imm8) . ((+ #xb0 r) ib)) 198 | ((mov r16 (imm16 imm8 imm label)) . (o16 (+ #xb8 r) iw)) 199 | ((mov r32 (imm32 imm16 imm8 imm label)) . (o32 (+ #xb8 r) id)) 200 | ((mov r/m8 r8) . (#x88 /r)) 201 | ((mov r/m16 r16) . (o16 #x89 /r)) 202 | ((mov r/m32 r32) . (o32 #x89 /r)) 203 | ((mov r8 r/m8) . (#x8a /r)) 204 | ((mov r16 r/m16) . (o16 #x8b /r)) 205 | ((mov r32 r/m32) . (o32 #x8b /r)) 206 | ((mov byte m (imm8 imm label)) . (#xc6 /0 ib)) 207 | ((mov word m (imm16 imm8 imm label)) . (o16 #xc7 /0 iw)) 208 | ((mov dword m (imm32 imm16 imm8 imm label)) . (o32 #xc7 /0 id)) 209 | ((mov sreg r/m16) . (#x8e /r)) 210 | ((mov r/m16 sreg) . (#x8c /r)) 211 | ((movsb) . (#xa4)) 212 | ((movsw) . (o16 #xa5)) 213 | ((movsd) . (o32 #xa5)) 214 | ((movzx r16 r/m8) . (o16 #x0f #xb6 /r)) 215 | ((movzx r32 (r/m8 r8)) . (o32 #x0f #xb6 /r)) 216 | ((movzx r32 byte m) . (o32 #x0f #xb6 /r)) 217 | ((movzx r32 (r/m16 r16)) . (o32 #x0f #xb7 /r)) 218 | ((movzx r32 word m) . (o32 #x0f #xb7 /r)) 219 | ,@(arith-syntax-2 'mul nil) 220 | ,@(arith-syntax-2 'neg nil) 221 | ((nop) . (#x90)) 222 | ,@(arith-syntax-2 'not nil) 223 | ,@(arith-syntax-1 'or nil) 224 | ((out imm8 r8) . (#xe6 ib)) ; (out imm8 al) 225 | ((out imm8 r16) . (#xe7 ib)) ; (out imm8 ax) 226 | ((out dx al) . (#xee)) 227 | ((out dx ax) . (#xef)) 228 | ((pop r16) . (o16 (+ #x58 r))) 229 | ;; Note that for 64 bit mode, prefix #x66 should be used according 230 | ;; to section 4.2 (INSTRUCTIONS (N-Z)) of [1]. This is different from NASM. 231 | ((popf) . (o16 #x9d)) 232 | ((push r16) . (o16 (+ #x50 r))) 233 | ;; Note that for 64 bit mode, prefix #x66 should be used according 234 | ;; to section 4.2 (INSTRUCTIONS (N-Z)) of [1]. This is different from NASM. 235 | ((pushf) . (o16 #x9c)) 236 | ((ret) . (#xc3)) 237 | ((rdmsr) . (#x0f #x32)) 238 | ,@(shift-syntax 'sal nil) 239 | ,@(shift-syntax 'sar nil) 240 | ,@(shift-syntax 'shl nil) 241 | ,@(shift-syntax 'shr nil) 242 | ((stc) . (#xf9)) 243 | ((std) . (#xfd)) 244 | ((sti) . (#xfb)) 245 | ((stosb) . (#xaa)) 246 | ((stosw) . (o16 #xab)) 247 | ((stosd) . (o32 #xab)) 248 | ,@(arith-syntax-1 'sbb nil) 249 | ,@(arith-syntax-1 'sub nil) 250 | ((test al imm8) . (#xa8 ib)) 251 | ((test ax imm16) . (#xa9 iw)) 252 | ((test (r/m8 r8) imm8) . (#xf6 /0 ib)) 253 | ((test byte m imm8) . (#xf6 /0 ib)) 254 | ((test r/m16 imm16) . (#xf7 /0 iw)) 255 | ((test word m imm16) . (#xf7 /0 iw)) 256 | ((test r/m32 imm32) . (#xf7 /0 id)) 257 | ((test dword m imm32) . (#xf7 /0 id)) 258 | ((test r/m8 r8) . (#x84 /r)) 259 | ((test r/m16 r16) . (#x85 /r)) 260 | ((test r/m32 r32) . (#x85 /r)) 261 | ((wrmsr) . (#x0f #x30)) 262 | ((xadd r/m8 r8) . (#x0f #xc0 /r)) 263 | ((xadd r/m16 r16) . (o16 #x0f #xc1 /r)) 264 | ((xadd r/m32 r32) . (o32 #x0f #xc1 /r)) 265 | ((xchg r16 ax) . (o16 (+ #x90 r))) 266 | ((xchg r32 eax) . (o32 (+ #x90 r))) 267 | ((xchg r/m8 r8) . (#x86 /r)) 268 | ((xchg r8 r/m8) . (#x86 /r)) 269 | ((xchg r/m16 r16) . (o16 #x87 /r)) 270 | ((xchg r16 r/m16) . (o16 #x87 /r)) 271 | ((xchg r/m32 r32) . (o32 #x87 /r)) 272 | ((xchg r32 r/m32) . (o32 #x87 /r)) 273 | ,@(arith-syntax-1 'xor nil)) 274 | "Valid for both 16-bit and 64-bit modes.") 275 | 276 | (defparameter *x86-64-syntax-16/32-bit-only* 277 | `(((call (imm16 imm8 label)) . (o16 #xe8 cw)) 278 | ((dec r16) . (o16 (+ #x48 r))) 279 | ((dec r32) . (o32 (+ #x48 r))) 280 | ((inc r16) . (o16 (+ #x40 r))) 281 | ((inc r32) . (o32 (+ #x40 r))) 282 | ((jcxz (imm8 label imm16 imm32)) . (a16 #xe3 cb)) 283 | ((jmp near (imm16 label imm8 imm32)) . (#xe9 cw)) 284 | ((mov r32 cr0-cr7) . (#x0f #x20 /r)) 285 | ((mov cr0-cr7 r32) . (#x0f #x22 /r)) 286 | ((pop r32) . (o32 (+ #x58 r))) 287 | ((pop ss) . (#x17)) 288 | ((pop ds) . (#x1f)) 289 | ((pop es) . (#x07)) 290 | ((popfd) . (o32 #x9d)) 291 | ((push r32) . (o32 (+ #x50 r))) 292 | ((push cs) . (#x0e)) 293 | ((push ss) . (#x16)) 294 | ((push ds) . (#x1e)) 295 | ((push es) . (#x06)) 296 | ((pushfd) . (o32 #x9c))) 297 | "Valid for 16-bit mode only.") 298 | 299 | (defparameter *x86-64-syntax-64-bit-only* 300 | `( 301 | ,@(arith-syntax-1 'adc t) 302 | ,@(arith-syntax-1 'add t) 303 | ,@(arith-syntax-1 'and t) 304 | ((bswap r64) . (rex.w #x0f (+ #xc8 r))) 305 | ,@(bit-syntax 'bt t) 306 | ,@(bit-syntax 'btc t) 307 | ,@(bit-syntax 'btr t) 308 | ,@(bit-syntax 'bts t) 309 | ((bsf r64 r/m64) . (rex.w #x0f #xbc /r)) 310 | ((bsr r64 r/m64) . (rex.w #x0f #xbd /r)) 311 | ((cmovcc r64 r/m64) . (rex.w #x0f (+ #x40 cc) /r)) 312 | ((cmpxchg r/m64 r64) . (rex.w #x0f #xb1 /r)) 313 | ((cmpxchg16b m) . (rex.w #x0f #xc7 /1)) 314 | ,@(arith-syntax-1 'cmp t) 315 | ((dec (r/m64 r64)) . (rex.w #xff /1)) 316 | ((dec qword m) . (rex.w #xff /1)) 317 | ,@(arith-syntax-2 'div t) 318 | ((inc (r/m64 r64)) . (rex.w #xff /0)) 319 | ((inc qword m) . (rex.w #xff /0)) 320 | ((iretq) . (rex.w #xcf)) 321 | ;; The following instruction is available for 16/32 bit, but we only support it 322 | ;; in 64 bit for simplicity (there are already more compact `jmp near` in 16/32 bits.) 323 | ((jmp near (imm32 label imm8 imm16 imm64)) . (#xe9 cd)) 324 | ((jmp near r/m64) . (#xff /4)) 325 | ((jrcxz (imm8 label imm16 imm32 imm64)) . (#xe3 cb)) 326 | ((leave) . (#xc9)) 327 | ((lodsq) . (rex.w #xad)) 328 | ;; For the following two instructions (including the one commented out) 329 | ;; we use id instead of io (as in instruction manual) for imm32. 330 | ;; NASM generates same results. 331 | ;; The following instruction is handled in function match-instruction, 332 | ;; therefore commented out. 333 | ;; ((mov r64 -imm32) . (rex.w #xc7 /0 id)) 334 | ((mov qword m (imm32 imm16 imm8 imm label)) . (rex.w #xc7 /0 id)) 335 | ((mov r64 (imm32 imm16 imm8 imm)) . ((+ #xb8 r) id)) 336 | ((mov r64 (imm64 label)) . (rex.w (+ #xb8 r) io)) 337 | ((mov r/m64 r64) . (rex.w #x89 /r)) 338 | ((mov r64 r/m64) . (rex.w #x8b /r)) 339 | ((movsq) . (rex.w #xa5)) 340 | ((movzx r64 (r/m8 r8)) . (rex.w #x0f #xb6 /r)) 341 | ((movzx r64 byte m) . (rex.w #x0f #xb6 /r)) 342 | ((movzx r64 (r/m16 r16)) . (rex.w #x0f #xb7 /r)) 343 | ((movzx r64 word m) . (rex.w #x0f #xb7 /r)) 344 | ,@(arith-syntax-2 'mul t) 345 | ,@(arith-syntax-2 'neg t) 346 | ,@(arith-syntax-2 'not t) 347 | ,@(arith-syntax-1 'or t) 348 | ((pop r64) . ((+ #x58 r))) 349 | ((popcnt r64 r/m64) . (#xf3 rex.w #x0f #xb8 /r)) 350 | ((popfq) . (#x9d)) 351 | ((push r64) . ((+ #x50 r))) 352 | ((pushfq) . (#x9c)) 353 | ((setcc r/m8) . (#x0f (+ #x90 cc) /0)) 354 | ,@(shift-syntax 'sal t) 355 | ,@(shift-syntax 'sar t) 356 | ,@(shift-syntax 'shl t) 357 | ,@(shift-syntax 'shr t) 358 | ,@(arith-syntax-1 'sbb t) 359 | ((stosq) . (rex.w #xab)) 360 | ,@(arith-syntax-1 'sub t) 361 | ((syscall) . (#x0f #x05)) 362 | ((sysret) . (#x0f #x07)) 363 | ((test rax imm32) . (rex.w #xa9 id)) 364 | ((test r/m64 imm32) . (rex.w #xf7 /0 id)) 365 | ((test qword m imm32) . (rex.w #xf7 /0 id)) 366 | ((test r/m64 r64) . (rex.w #x85 /r)) 367 | ((xadd r/m64 r64) . (rex.w #x0f #xc1 /r)) 368 | ((xchg r64 rax) . (rex.w (+ #x90 r))) 369 | ((xchg r/m64 r64) . (rex.w #x87 /r)) 370 | ((xchg r64 r/m64) . (rex.w #x87 /r)) 371 | ,@(arith-syntax-1 'xor t))) 372 | 373 | (defparameter *x86-64-syntax-16/32-bit* 374 | (append *x86-64-syntax-16/32-bit-only* *x86-64-syntax-common*) 375 | "Syntax table for 16-bit mode.") 376 | 377 | (defparameter *x86-64-syntax-64-bit* 378 | (append *x86-64-syntax-64-bit-only* *x86-64-syntax-common*) 379 | "Syntax table for 64-bit mode.") 380 | 381 | (defun x86-64-syntax (bits) 382 | "Returns syntax table according to bit mode (16, 32 or 64)." 383 | (ecase bits 384 | ((16 32) *x86-64-syntax-16/32-bit*) 385 | (64 *x86-64-syntax-64-bit*))) 386 | -------------------------------------------------------------------------------- /debug-qemu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Emulate with qemu, enabling debug settings for GDB. 3 | qemu-system-x86_64 -fda floppy.img -m 32 -monitor stdio -s -S 4 | -------------------------------------------------------------------------------- /debug-virtualbox: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Emulate with VirtualBox, enabling debug settings. 3 | VirtualBox --startvm yalo --debug 4 | -------------------------------------------------------------------------------- /doc/AssemblyX64.md: -------------------------------------------------------------------------------- 1 | Assembly syntax used by CL cross compiler and Ink 2 | ================================================= 3 | 4 | # Introduction 5 | 6 | Lisp Assembly Program (LAP) uses list structure to contain assembly 7 | code. Basically, atoms represent labels while lists represent (pseudo) 8 | instructions. Local labels (starting with a period) are also supported. 9 | 10 | Lisp expressions can be used for immediate values. In addition, since 11 | LAP is an S-expression, macros could be used to mimic the macro 12 | facility of *real* assemblers. 13 | 14 | The syntax is similar to what NASM uses. Basically, Intel syntax is 15 | used, i.e. destination operand precedes source operand. 16 | 17 | To get a feeling about what LAP looks like, one may take a look at the 18 | value of `*bootloader*` defined in https://github.com/whily/yalo/blob/master/cc/bootloader.lisp. 19 | 20 | # Pseudo Instructions of Assembly. 21 | 22 | Directives (e.g. bits, origin) are categorized as pseudo instructions 23 | here too. 24 | 25 | ## addressing: addressing mode 26 | 27 | Set the default setting of whether RIP Relative Addressing is used in 28 | 64 bit mode. This only applies when memory label is used (i.e. it does 29 | not affect the addressing options when registers are used, also it is 30 | not applicable to absolute address like #xb8000). One can use 31 | per-instruction override of `abs` or `rel` explicitly, for example: 32 | `(mov byte (abs msg) 0)`. 33 | 34 | | Instruction | Description | 35 | | -------------- | ------------------------------------------- | 36 | | addressing abs | Default to bsolute addresing | 37 | | addressing rel | Default to RIP Relative addresing (default) | 38 | 39 | ## align: boundary align 40 | 41 | The next instruction will be aligned at the boundary specified. NOP 42 | (#x90) will be inserted if necessary. 43 | 44 | | Instruction | Description | 45 | | -------------------------- | ------------- | 46 | | align 4 | 8 | 16 | | 47 | 48 | ## bits: Bit Mode 49 | 50 | | Instruction | Description | 51 | | ----------- | --------------------- | 52 | | bits 16 | 16-bit mode | 53 | | bits 64 | 64-bit mode (default) | 54 | 55 | ## db: Declaring initialized byte value(s) 56 | 57 | | Instruction | Description | 58 | | -------------------------------------- | ----------------------------- | 59 | | db (_number_ | _string_)* | Declare byte values via lists | 60 | 61 | Note: 62 | 63 | * _number_ should be in range -128..+255. Expression within the same 64 | range can be used as well. 65 | * _string_ is converted byte by byte. 66 | 67 | ## dw: Declaring initialized word value(s) 68 | 69 | | Instruction | Description | 70 | | ---------------------- | ------------------------------ | 71 | | dw (_number_)* | Declare word value via lists | 72 | 73 | Note: 74 | 75 | * _number_ should be in range -32,768..+65,535. Expression within the same 76 | range can be used as well. 77 | 78 | ## dd: Declaring initialized doubleword value(s) 79 | 80 | | Instruction | Description | 81 | | ---------------------- | ------------------------------------ | 82 | | dd (_number_)* | Declare doubleword value via lists | 83 | 84 | Note: 85 | 86 | * _number_ should be in range -2,147,483,648..+4,294,967,295. 87 | Expression within the same range can be used as well. 88 | 89 | ## dq: Declaring initialized quadword value(s) 90 | 91 | | Instruction | Description | 92 | | ---------------------- | ---------------------------------- | 93 | | dq (_number_)* | Declare quadword value via lists | 94 | 95 | Note: 96 | 97 | * _number_ should be in range 98 | -9,223,372,036,854,775,808..+18,446,744,073,709,551,615. 99 | Expression within the same range can be used as well. 100 | 101 | ## equ: Defint Constant 102 | 103 | | Instruction | Description | 104 | | ------------------ | ----------------------------------------- | 105 | | equ _const_ _expr_ | Define constant _const_ with value _expr_ | 106 | 107 | Note: 108 | 109 | * _expr_ should be evaulated when encoutering the instruction, 110 | i.e. forward reference is not allowed. 111 | 112 | ## org: Define Origin 113 | 114 | | Instruction | Description | 115 | | ----------- | ----------------------- | 116 | | org val | Define origin to be val | 117 | 118 | Note: 119 | 120 | * *org* can be used multiple times, however $$ refers to the latest definition of *org*. 121 | 122 | ## resb/resw/resd/resq: Declare unitialized data 123 | 124 | | Instruction | Description | 125 | | ----------- | ----------------------- | 126 | | resb _n_ | Reserve _n_ bytes | 127 | | resw _n_ | Reserve _n_ words | 128 | | resd _n_ | Reserve _n_ doublewords | 129 | | resq _n_ | Reserve _n_ quadwords | 130 | 131 | ## times: Repeat instruction = 132 | 133 | | Instruction | Description | 134 | | --------------------------- | --------------------------------------- | 135 | | times _count_ _instruction_ | Assemble _count_ times of _instruction_ | 136 | 137 | Note: 138 | 139 | * _count_ could be an expression which can be evaluated when *times* 140 | instruction is encoutered, e.g. containing $, $$, or labels defined 141 | before *times* instruction. 142 | * _instruction_ can be any other (pseudo) instructions. 143 | 144 | # Special Variables of Assembly. 145 | 146 | Following special variables are supported: 147 | * **$** Location of the start of current instruction. 148 | * **$$** Origin (start address) of current assembly program. 149 | 150 | # Overview of x86-64 Assembly 151 | 152 | ## Intruction 153 | 154 | This wiki lists the machine instructions supported by x86-64 LAP, and 155 | the short description of the functions for each instruction. One 156 | should refer to Intel or AMD manuals for complete reference. 157 | 158 | For each mnemonic, one table is provided to list the supported 159 | instructions. There are 2 columns in the table: 160 | * **Instruction**: documents mnemonic and operands. 161 | * **Opcode**: documents the translated opcode. 162 | 163 | ## Notations for Instructions 164 | 165 | Following notations are used: 166 | * **imm8**: immediate byte value in the range of -128..+255. 167 | * **imm16**: immediate word value in the range of -32,768..+65,535. 168 | * **imm32**: immediate doubleword value in the range of -2,147,483,648..+4,294,967,295. 169 | * **imm64**: immediate quadword value in the range of -9,223,372,036,854,775,808..+18,446,744,073,709,551,615.. 170 | * **r8**: one of the byte general-purpose registers: al, cl, dl, bl, ah, ch, dh, bh, bpl, spl, dil, and sil. 171 | * **r16**: one of the word general-purpose registers: ax, cx, dx, bx, sp, bp, si, di. 172 | * **r32**: one of the doubleword general-purpose registers: eax, ecx, edx, ebx, esp, ebp, esi, edi. 173 | * **r64**: one of the quadword general-purpose registers: rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8-r15. 174 | * **m8, m16, m32, m64, m128**: memory references. Specifier (`byte`, `word`, `dword`, `qword`) is needed for ambiguous cases. For example in `(mov word (12345) 16). 175 | * **m16&32**, **m16&16**, **m32&32**, **m16&64**, a memory operand containing one pair whose sizes are indicated on the left and right size of the ampersand. 176 | * **r/m8, r/m16, r/m32, r/m64**: register or memeory choices. For example, r/m8 means that either r8 or m8 can be used as operand. 177 | * **sreg**: segment register. 178 | 179 | ## Range of Immediate Values 180 | 181 | Note that the range for imm8/16/32/64 is defined considering the 182 | capcity of 8/16/32/64 bits. The range might be too broad for jmp like 183 | instructions which require *true* signed integers, however the impact 184 | is minimal. 185 | 186 | In 64 bit mode, the default operand size is 32 bit. REX.W is used for 187 | 64 bit operand size. When 32 bit register is used as target, the 188 | result is automatically sign extended to 64 bit. To reduce the 189 | generated machine code size, the assembler automatically use the 32 190 | bit operand size if immediate value can be represented as 32 bits. For 191 | example, `(mov eax 1)` and `(mov rax 1)` generates same machine 192 | code. Note that such optimization is mainly meaningful for *mov* 193 | instructions, as sign extension to 64 bit is generally not applicable 194 | for other instructions unless the upper 32 bits are always 0. 195 | 196 | ## Memory Address Operands 197 | 198 | Memory address operands are supported, e.g. `(bp)`, `(var)`, `(bp si 199 | 5)`. Note that the order is flexible. For example, `(bp si 3)` is 200 | equivalent to `(si 3 bp)`. 201 | 202 | For scaled index of 32-bit addressing modes, one has to use the form 203 | of register*scale, e.g. eax*8. 204 | 205 | Segment override prefix is used purely as a prefix, e.g. `(es mov al 206 | (di))`, which is different from traditional syntax. The motiviation is 207 | to use a simple method to handle this case as such override is not 208 | used in 64 bit mode. 209 | 210 | ## Notations for Opcodes 211 | 212 | Following notations are used: 213 | * A hex number, such as CC, indicates a fixed byte containing that number. 214 | * A hex number followed by **+r**, like **B0+r**, indicates that one of the operands is a register, and correspondign register value should be added to the opcode. 215 | * **/n** (where n is 0 to 7): indictes that one of the operand is r/m, and the field Reg/Opcode should be encoded with n. 216 | * **/r**: ModR/M byte of the instruction contains a register operand (encoded in field Reg/Opcode) and an r/m operand (encoded in field R/M). 217 | * **cb, cw, cd, co**: one of the operands is an immediate value, and the _difference_ between this value and the end address of the instruction is to be encoded as byte (cb), little-endian word (cw), little-endian doubleword (cd), and little-endian quadword (co) respectively. 218 | * **ib, iw, id, io**: one of the operands is an immediate value, and it is to be encoded as byte (ib), little-endian word (iw), little-endian doubleword (id), and little-endian quadword (io) respectively. 219 | * **o16, o32**: operand-size override prefix. o16 generates no code in 16-bit mode, but indicates a 66h prefix in 32/64-bit mode; similarly, o32 generates no code in 32/64-bit mode, but indicates a 66h prefix in 16-bit mode. 220 | * **a16, a32**: address-size override prefix. a16 generates no code in 16-bit mode, but indicates a 67h prefix in 32/64-bit mode; similarly, a32 generates no code in 32-bit mode, but indicates a 67h prefix in 16/64-bit mode. 221 | * **rex.w**: REX prefix indicating 64 bit operand, in 64 bit mode. 222 | 223 | Note that REX prefix are not used in opcode notations. The prefix is 224 | automatically generated by analyzing the operands. 225 | 226 | ### Conditional Codes 227 | 228 | Conditional codes are used for Jcc, CMOVcc, and SETcc instructions, which are 229 | encoded as (+ xx cc). Meaning of conditional codes are listed below. 230 | 231 | | cc | value | trigger flag | 232 | | -------- | ----- | ------------ | 233 | | o | 0 | overflow flag set | 234 | | no | 1 | overflow flag not set | 235 | | b c nae | 2 | carry flag set | 236 | | ae nb nc | 3 | carry flag not set | 237 | | e z | 4 | zero flag set | 238 | | ne nz | 5 | zero flag not set | 239 | | be na | 6 | either of carry or zero flag set | 240 | | a nbe | 7 | neither carry nor zero flag set | 241 | | s | 8 | sign flag set | 242 | | ns | 9 | sign flag not set | 243 | | p pe | 10 | parity flag set | 244 | | np po | 11 | parity flag not set | 245 | | l nge | 12 | exactly one of sign and overflow flag is set | 246 | | ge nl | 13 | opposite case of above | 247 | | le ng | 14 | either the zero flag is set, or exactly one of sign and overflow flag is set | 248 | | g nle | 15 | opposite case of above | 249 | 250 | # Instruction set 251 | 252 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 253 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 254 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 255 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 256 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 257 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 258 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 259 | -------------------------------------------------------------------------------- /doc/AssemblyX64A.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set A 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | A [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### adc: Add with Carry 14 | 15 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details. 16 | 17 | ### add: Add 18 | 19 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details. 20 | 21 | ### and: Logical AND 22 | 23 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details. 24 | -------------------------------------------------------------------------------- /doc/AssemblyX64Arith.md: -------------------------------------------------------------------------------- 1 | x86-64 Arithmetic Instruction 2 | ============================= 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64B.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | There are 8 arithmetic instructions which have similar formats of 14 | instructions. They are discussed together here. 15 | 16 | The instructions are: 17 | * adc: add with carry 18 | * add: add 19 | * and: logical and 20 | * cmp: compare 21 | * or: logical or 22 | * sbb: subtract with borrow 23 | * sub: subtract 24 | * xor: logical exclusive or 25 | 26 | The format of the instructions are given below. 27 | 28 | | Instruction | Opcode | 29 | | --------------- | ------------------------ | 30 | | ins al imm8 | (+ base 04) ib | 31 | | ins ax imm16 | o16 (+ base 05) iw | 32 | | ins eax imm32 | o32 (+ base 05) id | 33 | | ins rax imm32 | REX.W (+ base 05) id | 34 | | ins r/m8 imm8 | 80 opcode ib | 35 | | ins r/m16 imm16 | o16 81 opcode iw | 36 | | ins r/m32 imm32 | o32 81 opcode id | 37 | | ins r/m64 imm32 | REX.W 81 opcode id | 38 | | ins r/m16 imm8 | o16 83 opcode ib | 39 | | ins r/m32 imm8 | o32 83 opcode ib | 40 | | ins r/m64 imm8 | REX.W 83 opcode ib | 41 | | ins r/m8 r8 | base /r | 42 | | ins r/m16 r16 | o16 (+ base 01) /r | 43 | | ins r/m32 r32 | o32 (+ base 01) /r | 44 | | ins r/m64 r64 | REX.W (+ base 01) /r | 45 | | ins r8 r/m8 | (+ base 02) /r | 46 | | ins r16 r/m16 | o16 (+ base 03) /r | 47 | | ins r32 r/m32 | o32 (+ base 03) /r | 48 | | ins r64 r/m64 | REX.W (+ base 03) /r | 49 | 50 | Base and opcode in above table are given below for each instruction. 51 | 52 | | Instruction | Base (hexadecimal) | Opcode | 53 | | ----------- | ------------------ | ------ | 54 | | adc | 10 | /2 | 55 | | add | 00 | /0 | 56 | | and | 20 | /4 | 57 | | cmp | 38 | /7 | 58 | | or | 08 | /1 | 59 | | sbb | 18 | /3 | 60 | | sub | 28 | /5 | 61 | | xor | 30 | /6 | 62 | -------------------------------------------------------------------------------- /doc/AssemblyX64B.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set B 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) B [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### bsf: Bit Scan Forward 14 | 15 | | Instruction | Opcode | 16 | | ------------- | -------------- | 17 | | bsf r16 r/m16 | o16 0F BC /r | 18 | | bsf r32 r/m32 | o32 0F BC /r | 19 | | bsf r64 r/m64 | REX.W 0F BC /r | 20 | 21 | ### bsf: Bit Scan Reverse 22 | 23 | | Instruction | Opcode | 24 | | ------------- | -------------- | 25 | | bsr r16 r/m16 | o16 0F BD /r | 26 | | bsr r32 r/m32 | o32 0F BD /r | 27 | | bsr r64 r/m64 | REX.W 0F BD /r | 28 | 29 | ### bswap: Byte Swap 30 | 31 | | Instruction | Opcode | 32 | | ----------- | -------------- | 33 | | bswap r32 | 0F C8+r | 34 | | bswap r64 | REX.W 0F C8+r | 35 | 36 | ### bt: Bit Test 37 | 38 | Please refer to [x86-64 bit instructions](AssemblyX64Bit.md) for details. 39 | 40 | ### btc: Bit Test and Complement 41 | 42 | Please refer to [x86-64 bit instructions](AssemblyX64Bit.md) for details. 43 | 44 | ### btr: Bit Test and Reset 45 | 46 | Please refer to [x86-64 bit instructions](AssemblyX64Bit.md) for details. 47 | 48 | ### bts: Bit Test and Set 49 | 50 | Please refer to [x86-64 bit instructions](AssemblyX64Bit.md) for details. 51 | -------------------------------------------------------------------------------- /doc/AssemblyX64Bit.md: -------------------------------------------------------------------------------- 1 | x86-64 Bit Instruction 2 | ============================= 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64B.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | There are 4 bit instructions which have similar formats of 14 | instructions. They are discussed together here. 15 | 16 | The instructions are: 17 | * bt: bit test 18 | * btc: bit test and complement 19 | * btr: bit test and reset 20 | * bts: bit test and set 21 | 22 | The format of the instructions are given below. 23 | 24 | | Instruction | Opcode | 25 | | -------------- | ----------------------- | 26 | | ins r/m16 r16 | 0F (+ base A3) /r | 27 | | ins r/m32 r32 | 0F (+ base A3) /r | 28 | | ins r/m32 r32 | 0F (+ base A3) /r | 29 | | ins r/m16 imm8 | 0F BA opcode ib | 30 | | ins r/m32 imm8 | 0F BA opcode ib | 31 | | ins r/m64 imm8 | REX.W 0F BA opcode ib | 32 | 33 | Base and opcode in above table are given below for each instruction. 34 | 35 | | Instruction | Base (hexadecimal) | Opcode | 36 | | ----------- | ------------------ | ------ | 37 | | bt | 0 | /4 | 38 | | btc | 18 | /7 | 39 | | btr | 10 | /6 | 40 | | bts | 8 | /5 | 41 | -------------------------------------------------------------------------------- /doc/AssemblyX64C.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set C 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) C 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### call: Call Procedure 14 | 15 | | Instruction | Opcode | 16 | | ----------- | ---------- | 17 | | call imm16 | o16 E8 cw | 18 | | call imm32 | o32 E8 cd | 19 | 20 | ### clc: Clear Carry Flag 21 | 22 | | Instruction | Opcode | 23 | | ----------- | ------ | 24 | | clc | F8 | 25 | 26 | ### cld: Clear Direction Flag 27 | | Instruction | Opcode | 28 | | ----------- | ------ | 29 | | cld | FC | 30 | 31 | ### cli: Clear Interrupt Flag 32 | 33 | | Instruction | Opcode | 34 | | ----------- | ------ | 35 | | cli | FA | 36 | 37 | ### cmovcc: Conditional Move 38 | 39 | | Instruction | Opcode | 40 | | ----------------- | --------------------- | 41 | | cmovcc r16 r/m16 | o16 0F (+ 40 cc) /r | 42 | | cmovcc r32 r/m32 | o32 0F (+ 40 cc) /r | 43 | | cmovcc r64 r/m64 | REX.W 0F (+ 40 cc) /r | 44 | 45 | Please refer [x86-64 conditional codes](AssemblyX64.md#conditional-codes) for details. 46 | 47 | ### cmp: Compare 48 | 49 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details. 50 | 51 | ### cmpxchg: Compare and Exchange 52 | 53 | | Instruction | Opcode | 54 | | ----------------- | ------------------ | 55 | | cmpxchg r/m8 r8 | 0F B0 /r | 56 | | cmpxchg r/m16 r16 | o16 0F B1 /r | 57 | | cmpxchg r/m32 r32 | o32 0F B1 /r | 58 | | cmpxchg r/m64 r64 | REX.W 0F B1 /r | 59 | 60 | ### cmpxchg8b/cmpxchg16b: Compare and Exchange Bytes 61 | 62 | | Instruction | Opcode | 63 | | --------------- | -------------- | 64 | | cmpxchg8b m64 | 0F C7 /1 | 65 | | cmpxchg16b m128 | REX.W 0F C7 /1 | 66 | -------------------------------------------------------------------------------- /doc/AssemblyX64D.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set D 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | D [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### dec: Decrement by 1 14 | 15 | | Instruction | Opcode | 16 | | ----------- | ----------- | 17 | | dec r/m8 | FE /1 | 18 | | dec r/m16 | o16 FF /1 | 19 | | dec r/m32 | o32 FF /1 | 20 | | dec r/m64 | REX.W FF /1 | 21 | | dec r16 | o16 48+r | 22 | | dec r32 | o32 48+r | 23 | 24 | ### div: Unsigned Divide 25 | 26 | | Instruction | Opcode | 27 | | ----------- | ----------- | 28 | | div r/m8 | F6 /6 | 29 | | div r/m16 | o16 F7 /6 | 30 | | div r/m32 | o32 F7 /6 | 31 | | div r/m64 | REX.W F7 /6 | 32 | -------------------------------------------------------------------------------- /doc/AssemblyX64E.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set E 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) E [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | Placeholder 14 | -------------------------------------------------------------------------------- /doc/AssemblyX64F.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set F 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) F 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | Placeholder 14 | -------------------------------------------------------------------------------- /doc/AssemblyX64H.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set H 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | H [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | hlt: Halt 14 | --------- 15 | 16 | | Instruction | Opcode | 17 | | ----------- | ------ | 18 | | hlt | F4 | 19 | -------------------------------------------------------------------------------- /doc/AssemblyX64I.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set I 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) I [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### in: Input from Port 14 | 15 | | Instruction | Opcode | 16 | | ----------- | ------ | 17 | | in al imm8 | E4 ib | 18 | | in ax imm8 | E5 ib | 19 | | in al dx | EC | 20 | | in ax dx | ED | 21 | 22 | ### inc: Increment by 1 23 | 24 | | Instruction | Opcode | 25 | | ----------- | ----------- | 26 | | inc r/m8 | FE /0 | 27 | | inc r/m16 | o16 FF /0 | 28 | | inc r/m32 | o32 FF /0 | 29 | | inc r/m64 | REX.W FF /0 | 30 | | inc r16 | o16 40+r | 31 | | inc r32 | o32 40+r | 32 | 33 | ### int: Call Interrupt Procedure 34 | 35 | | Instruction | Opcode | 36 | | ----------- | ------ | 37 | | int 3 | CC | 38 | | int imm8 | CD ib | 39 | 40 | ### invlpg: Invalidate TLB entries 41 | 42 | | Instruction | Opcode | 43 | | ----------- | -------- | 44 | | invlpg m | 0F 01 /7 | 45 | 46 | ### iretq: Interrupt Return 47 | 48 | | Instruction | Opcode | 49 | | ----------- | -------- | 50 | | iretq | REX.W CF | 51 | -------------------------------------------------------------------------------- /doc/AssemblyX64J.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set J 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) J 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### jcc: Conditional Branch 14 | 15 | | Instruction | Opcode | 16 | | -------------- | --------------- | 17 | | jcc imm | (+ 70 cc) cb | 18 | | jcc near imm | 0F (+ 80 cc) cd | 19 | | jcxz imm | a16 E3 cb | 20 | | jecxz imm | a32 E3 cb | 21 | | jrcxz imm | E3 cb | 22 | 23 | Please refer to [conditional codes](AssemblyX64.md) for details. 24 | 25 | ### jmp: Jump 26 | 27 | | Instruction | Opcode | 28 | | -------------- | -------- | 29 | | jmp short imm | EB cb | 30 | | jmp near imm | E9 cw (for 16/32 bits) | 31 | | jmp near imm | E9 cd (for 64 bit) | 32 | | jmp near r/m64 | FF /4 | 33 | -------------------------------------------------------------------------------- /doc/AssemblyX64L.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set L 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | L [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### leave: High Level Procedure Exit 14 | 15 | | Instruction | Opcode | 16 | | ----------- | -------- | 17 | | leave | C9 | 18 | 19 | 20 | ### lgdt/lidt/lldt: Load Descriptor Tables 21 | 22 | | Instruction | Opcode | 23 | | ----------- | -------- | 24 | | lgdt m16&32 | 0F 01 /2 | 25 | | lidt m16&32 | 0F 01 /3 | 26 | | lldt r/m16 | 0F 00 /2 | 27 | 28 | ### lodsb/lodsw: Load String 29 | 30 | | Instruction | Opcode | 31 | | ----------- | -------- | 32 | | lodsb | AC | 33 | | lodsw | o16 AD | 34 | | lodsd | o32 AD | 35 | | lodsq | REX.W AD | 36 | 37 | ### loop: Loop According to (E)CX Counter 38 | 39 | | Instruction | Opcode | 40 | | ----------- | ------ | 41 | | loop imm16 | E2 cb | 42 | -------------------------------------------------------------------------------- /doc/AssemblyX64M.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set M 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) M [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### mov: Move 14 | 15 | | Instruction | Opcode | 16 | | --------------- | -------------- | 17 | | mov r8 imm8 | B0+r ib | 18 | | mov r16 imm16 | o16 B8+r iw | 19 | | mov r32 imm32 | o32 B8+r id | 20 | | mov r64 imm64 | REX.W B8+r io | 21 | | mov r/m8 r8 | 88 /r | 22 | | mov r/m16 r16 | o16 89 /r | 23 | | mov r/m32 r32 | o32 89 /r | 24 | | mov r/m64 r64 | REX.W 89 /r | 25 | | mov r8 r/m8 | 8A /r | 26 | | mov r16 r/m16 | o16 8B /r | 27 | | mov r32 r/m32 | o32 8B /r | 28 | | mov r64 r/m64 | REX.W 8B /r | 29 | | mov r/m8 imm8 | C6 /0 ib | 30 | | mov r/m16 imm16 | o16 C7 /0 iw | 31 | | mov r/m32 imm32 | o32 C7 /0 id | 32 | | mov r/m64 imm32 | REX.W C7 /0 id | 33 | | mov sreg r/m16 | 8E /r | 34 | | mov r/m16 sreg | 8C /r | 35 | 36 | ### mov: Move to/from Control Registers 37 | 38 | | Instruction | Opcode | 39 | | --------------- | ------------ | 40 | | mov r32 cr0-cr7 | 0F 20 /r | 41 | | mov cr0-cr7 r32 | 0F 22 /r | 42 | 43 | ### movsb/movsw: Move Data from String to String 44 | 45 | | Instruction | Opcode | 46 | | ----------- | -------- | 47 | | movsb | A4 | 48 | | movsw | o16 A5 | 49 | | movsd | o32 A5 | 50 | | movsq | REX.W A5 | 51 | 52 | ### movzx: Move with Zero-Extend 53 | 54 | | Instruction | Opcode | 55 | | --------------- | -------------- | 56 | | movzx r16 r/m8 | o16 0F B6 /r | 57 | | movzx r32 r/m8 | o32 0F B6 /r | 58 | | movzx r64 r/m8 | REX.W 0F B6 /r | 59 | | movzx r32 r/m16 | o32 0F B7 /r | 60 | | movzx r64 r/m16 | REX.W 0F B7 /r | 61 | 62 | ### mul: Unsigned Multiply 63 | 64 | | Instruction | Opcode | 65 | | ----------- | ----------- | 66 | | mul r/m8 | F6 /4 | 67 | | mul r/m16 | o16 F7 /4 | 68 | | mul r/m32 | o32 F7 /4 | 69 | | mul r/m64 | REX.W F7 /4 | 70 | -------------------------------------------------------------------------------- /doc/AssemblyX64N.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set N 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) N 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### neg: Two's Complement Negation 14 | 15 | | Instruction | Opcode | 16 | | ----------- | ----------- | 17 | | neg r/m8 | F6 /3 | 18 | | neg r/m16 | o16 F7 /3 | 19 | | neg r/m32 | o32 F7 /3 | 20 | | neg r/m64 | REX.W F7 /3 | 21 | 22 | Replaces the value of destination operand with its two's complement (-dest). 23 | 24 | ### nop: No Operation 25 | 26 | | Instruction | Opcode | 27 | | ----------- | ------ | 28 | | nop | 90 | 29 | 30 | ### not: One's Complement Negation 31 | 32 | | Instruction | Opcode | 33 | | ----------- | ----------- | 34 | | not r/m8 | F6 /2 | 35 | | not r/m16 | o16 F7 /2 | 36 | | not r/m32 | o32 F7 /2 | 37 | | not r/m64 | REX.W F7 /2 | 38 | 39 | Replaces the value of destination operand with its one's complement (bitwise NOT). 40 | -------------------------------------------------------------------------------- /doc/AssemblyX64O.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set O 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | O [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### or: Logical Inclusive OR 14 | 15 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details. 16 | 17 | ### out: Output from Port 18 | 19 | | Instruction | Opcode | 20 | | ----------- | ------ | 21 | | out imm8 al | E6 ib | 22 | | out imm8 ax | E7 ib | 23 | | out dx al | EE | 24 | | out dx ax | EF | 25 | -------------------------------------------------------------------------------- /doc/AssemblyX64P.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set P 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) P [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### pop: Pop a Value from the Stack 14 | 15 | | Instruction | Opcode | 16 | | ----------- | -------- | 17 | | pop r16 | o16 58+r | 18 | | pop r32 | o32 58+r | 19 | | pop r64 | 58+r | 20 | | pop ss | 17 | 21 | | pop ds | 1F | 22 | | pop es | 07 | 23 | | popf | o16 9D | 24 | | popfd | o32 9D | 25 | | popfq | 9D | 26 | 27 | ### popcnt: Return the Count of the Number of Bits Set to 1 28 | 29 | | Instruction | Opcode | 30 | | ---------------- | ----------------- | 31 | | popcnt r64 r/m64 | F3 REX.W 0F B8 /r | 32 | 33 | ### push: Push a Value Onto the Stack 34 | 35 | | Instruction | Opcode | 36 | | ----------- | -------- | 37 | | push r16 | o16 50+r | 38 | | push r32 | o32 50+r | 39 | | push r64 | 50+r | 40 | | push cs | 0E | 41 | | push ss | 16 | 42 | | push ds | 1E | 43 | | push es | 06 | 44 | | pushf | o16 9C | 45 | | pushfd | o32 9C | 46 | | pushfq | 9C | 47 | -------------------------------------------------------------------------------- /doc/AssemblyX64R.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set R 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) R 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### rdmsr: Read From Model Specific Register 14 | 15 | | Instruction | Opcode | 16 | | ----------- | ------ | 17 | | rdmsr | 0F 32 | 18 | 19 | ### rep: Repeat String Operation Prefix 20 | 21 | Following are examples. 22 | 23 | | Instruction | Opcode | 24 | | ----------- | ------ | 25 | | rep movsb | F3 A4 | 26 | | rep movsw | F3 A5 | 27 | 28 | Note 29 | 30 | *rep* is a kind of prefix. 31 | 32 | ### ret: Return From Procedure 33 | 34 | | Instruction | Opcode | 35 | | ----------- | ------ | 36 | | ret | C3 | 37 | -------------------------------------------------------------------------------- /doc/AssemblyX64S.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set S 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | S [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### sbb: subtract with borrow 14 | 15 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details. 16 | 17 | ### sal/sar/shl/shr: Shift 18 | 19 | | Instruction | Opcode | 20 | | -------------- | ------------------ | 21 | | ins r/m8, 1 | D0 opcode | 22 | | ins r/m8, cl | D2 opcode | 23 | | ins r/m8, imm8 | C0 opcode ib | 24 | | ins r/m16 1 | o16 D1 opcode | 25 | | ins r/m16 cl | o16 D3 opcode | 26 | | ins r/m16 imm8 | o16 C1 opcode ib | 27 | | ins r/m32 1 | o32 D1 opcode | 28 | | ins r/m32 cl | o32 D3 opcode | 29 | | ins r/m32 imm8 | o32 C1 opcode ib | 30 | | ins r/m64 1 | REX.W D1 opcode | 31 | | ins r/m64 cl | REX.W D3 opcode | 32 | | ins r/m64 imm8 | REX.W C1 opcode ib | 33 | 34 | The opcodes are /4, /7, /4, 5 for sal, sar, shl, shr, respectively. 35 | 36 | Note that sal and shl perform the same operation. 37 | 38 | ### setcc: Set Byte on Condition 39 | 40 | | Instruction | Opcode | 41 | | ----------------- | --------------------- | 42 | | setcc r/m8 | 0F (+ 90 cc) /0 | 43 | 44 | Please refer [x86-64 conditional codes](AssemblyX64.md#conditional-codes) for details. 45 | 46 | ### stc: Set Carry Flag 47 | 48 | | Instruction | Opcode | 49 | | ----------- | ------ | 50 | | stc | F9 | 51 | 52 | ### std: Set Direction Flag 53 | | Instruction | Opcode | 54 | | ----------- | ------ | 55 | | std | FD | 56 | 57 | ### sti: Set Interrupt Flag 58 | 59 | | Instruction | Opcode | 60 | | ----------- | ------ | 61 | | sti | FB | 62 | 63 | ### stosb/stosw/stosd: Store String 64 | 65 | | Instruction | Opcode | 66 | | ----------- | -------- | 67 | | stosb | AA | 68 | | stosw | o16 AB | 69 | | stosd | o32 AB | 70 | | stosq | REX.W AB | 71 | 72 | ### sub: Sub 73 | 74 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details. 75 | 76 | ### syscall/sysret: (Return from) Fast System Call 77 | 78 | | Instruction | Opcode | 79 | | ----------- | ------ | 80 | | syscall | 0F 05 | 81 | | sysret | 0F 07 | 82 | -------------------------------------------------------------------------------- /doc/AssemblyX64T.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set T 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) T [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | ### test: Logical Compare 14 | 15 | | Instruction | Opcode | 16 | | ---------------- | -------------- | 17 | | test al imm8 | A8 ib | 18 | | test ax imm16 | A9 iw | 19 | | test rax imm32 | REX.W A9 id | 20 | | test r/m8 imm8 | F6 /0 ib | 21 | | test r/m16 imm16 | F7 /0 iw | 22 | | test r/m32 imm32 | F7 /0 id | 23 | | test r/m64 imm32 | REX.W F7 /0 id | 24 | | test r/m8 r8 | 84 /r | 25 | | test r/m16 r16 | 85 /r | 26 | | test r/m32 r32 | 85 /r | 27 | | test r/m64 r64 | REX.W85 /r | 28 | 29 | After ANDing the two operands, flags SF, ZF, and PF are set according 30 | to the result. The destination operand is *not* modified. 31 | -------------------------------------------------------------------------------- /doc/AssemblyX64U.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set U 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) U 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | Placeholder 14 | -------------------------------------------------------------------------------- /doc/AssemblyX64V.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set V 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | V [W](AssemblyX64W.md) [X](AssemblyX64X.md) 12 | 13 | Placeholder 14 | -------------------------------------------------------------------------------- /doc/AssemblyX64W.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set W 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) W [X](AssemblyX64X.md) 12 | 13 | ### wrmsr: Write to Model Specific Register 14 | 15 | | Instruction | Opcode | 16 | | ----------- | ------ | 17 | | wrmsr | 0F 30 | 18 | -------------------------------------------------------------------------------- /doc/AssemblyX64X.md: -------------------------------------------------------------------------------- 1 | x86-64 Instruction Set X 2 | ======================== 3 | 4 | [Assembly syntax](AssemblyX64.md) 5 | [A](AssemblyX64A.md) [B](AssemblyX64B.md) [C](AssemblyX64C.md) 6 | [D](AssemblyX64D.md) [E](AssemblyX64E.md) [F](AssemblyX64F.md) 7 | [H](AssemblyX64H.md) [I](AssemblyX64I.md) [J](AssemblyX64J.md) 8 | [L](AssemblyX64L.md) [M](AssemblyX64M.md) [N](AssemblyX64N.md) 9 | [O](AssemblyX64O.md) [P](AssemblyX64P.md) [R](AssemblyX64R.md) 10 | [S](AssemblyX64S.md) [T](AssemblyX64T.md) [U](AssemblyX64U.md) 11 | [V](AssemblyX64V.md) [W](AssemblyX64W.md) X 12 | 13 | ### xadd: Exchange and Add 14 | 15 | | Instruction | Opcode | 16 | | -------------- | -------------- | 17 | | xadd r/m8 r8 | 0F C0 /r | 18 | | xadd r/m16 r16 | o16 0F C1 /r | 19 | | xadd r/m32 r32 | o32 0F C1 /r | 20 | | xadd r/m64 r64 | REX.W 0F C1 /r | 21 | 22 | ### xchg: Exchange 23 | 24 | | Instruction | Opcode | 25 | | -------------- | ----------- | 26 | | xchg ax r16 | o16 90+r | 27 | | xchg r16 ax | o16 90+r | 28 | | xchg eax r32 | o32 90+r | 29 | | xchg r32 eax | o32 90+r | 30 | | xchg rax r64 | REX.W 90+r | 31 | | xchg r64 rax | REX.W 90+r | 32 | | xchg r/m8 r8 | 86 /r | 33 | | xchg r8 r/m8 | 86 /r | 34 | | xchg r/m16 r16 | o16 87 /r | 35 | | xchg r16 r/m16 | o16 87 /r | 36 | | xchg r/m32 r32 | o32 87 /r | 37 | | xchg r32 r/m32 | o32 87 /r | 38 | | xchg r/m64 r64 | REX.W 87 /r | 39 | | xchg r64 r/m64 | REX.W 87 /r | 40 | 41 | Note that when a memory operand is referenced, lock protocal is 42 | automatically implemented, regardless whether LOCK prefix is used or 43 | not. This may has impact on performance. 44 | 45 | ### xor: Logical Exclusive OR 46 | 47 | Please refer to [x86-64 arithmetic instructions](AssemblyX64Arith.md) for details. 48 | -------------------------------------------------------------------------------- /doc/CrossCompilation.md: -------------------------------------------------------------------------------- 1 | Cross Compilation 2 | ================= 3 | 4 | # Plan 5 | 6 | Below is the initial thinking on the plan to cross compile and 7 | bootstrap Yalo. 8 | 9 | ## Cross compile the minimal bootloader and Ink interpreter 10 | 11 | The milestone of this stage is to generate a minimal bootloader (OS is 12 | far away) which finally runs an Ink interpreter. 13 | 14 | * Input: a minimal version of Ink interpreter written in Ink 15 | * Cross compiling platform: x86-64 assembler and a 16 | minimal version of Ink compiler, both written in Common Lisp. The 17 | compiler may use some intermediate language (e.g. LLVM IR). 18 | 19 | ## Develop Ink compiler with Ink interpreter 20 | 21 | Once the minimal Ink interpreter is up, the main target is then to 22 | implement basic file system (ext2) support. The interpreter then is 23 | able to read/write Ink source files, which can then be put under 24 | version control via the interface between VM and host machine. 25 | 26 | The next milestone is to implement x86-64 assembler and a full fledged 27 | Ink compiler, both in Ink itself. 28 | -------------------------------------------------------------------------------- /run-bochs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Emulate with bochs. 3 | bochs -n -q -rc bochs-debug-cmds \ 4 | 'boot: a' \ 5 | 'floppya: 1_44=floppy.img, status=inserted' \ 6 | 'megs: 32' \ 7 | 'magic_break: enabled=1' \ 8 | 'cpuid: x86_64=1' \ 9 | 'vga: extension=vbe' \ 10 | 'display_library: sdl2, options="fullscreen,gui_debug"' 11 | -------------------------------------------------------------------------------- /run-qemu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Emulate with qemu. 3 | qemu-system-x86_64 -fda floppy.img -m 32 -monitor stdio 4 | -------------------------------------------------------------------------------- /run-virtualbox: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Emulate with VirtualBox. 3 | VirtualBox --startvm yalo 4 | -------------------------------------------------------------------------------- /scripts/build-bochs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Run the script in the root directory of bochs source. 3 | # Based on 4 | # https://git.archlinux.org/svntogit/community.git/tree/trunk/PKGBUILD?h=packages/bochs 5 | # https://wiki.osdev.org/Bochs#Compiling_Bochs_from_Source 6 | 7 | sed -i 's/2\.6\*|3\.\*)/2.6*|3.*|4.*)/' configure* 8 | 9 | ./configure \ 10 | --prefix=/usr \ 11 | --without-wx \ 12 | --enable-cpu-level=6 \ 13 | --enable-fpu \ 14 | --enable-3dnow \ 15 | --enable-disasm \ 16 | --enable-smp \ 17 | --enable-x86-64 \ 18 | --enable-avx \ 19 | --enable-long-phy-address \ 20 | --enable-disasm \ 21 | --enable-pcidev \ 22 | --enable-pci \ 23 | --enable-usb \ 24 | --enable-sb16=dummy \ 25 | --enable-cdrom \ 26 | --enable-debugger \ 27 | --enable-x86-debugger \ 28 | --enable-debugger-gui \ 29 | --enable-iodebug \ 30 | --enable-logging \ 31 | --with-x --with-x11 --with-term --with-sdl2 \ 32 | #--enable-all-optimizations 33 | --disable-docbook \ 34 | --disable-plugins 35 | 36 | sed -i 's/^LIBS = /LIBS = -lpthread/g' Makefile 37 | 38 | make -j5 && sudo make install 39 | -------------------------------------------------------------------------------- /write-kernel-sbcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sbcl --script 2 | 3 | (require 'asdf) 4 | (asdf:oos 'asdf:load-op 'cc) 5 | (in-package :cc) 6 | (write-kernel "floppy.img") 7 | --------------------------------------------------------------------------------